A. Entertainment in MAC 题意 有一个字符串和偶数, 你可以对这个字符串进行次操作(不能多不能少)
操作一:将的反向字符串拼接到s的后面,比如对字符串abc进行操作会变成 abccba
操作二:将当前的字符串反转
问进行完这n次操作后,最终的字符串的字典序最小的可能是什么样子的。
思路 可以发现,如果这个字符串翻转后更大(比如abc ,进行翻转后是cba 比原先更大了),那么我们就可以进行n次翻转,这样最终的字符串就是原先的字符串,也就实现最小了。
如果这个字符串s在反转后更小了,那么我们就必须执行奇数次翻转,才能保证这个s最终是较小的。但题目中说n是偶数,所以就意味着我们必须进行至少一次拼接操作, 那么显而易见,拼接操作进行的越少越好, 因此需要翻转次,然后拼接一次。 (比如bca, 如果进行偶数次翻转,那么最终的字符串前三个字符是bca ,而进行奇数次翻转时最终的字符串的前三个字符是acb 一定更小)
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;void solve () { int n; cin>>n; string str; cin>>str; string rs = str; reverse (rs.begin (),rs.end ()); if (rs < str){ cout<<(rs + str)<<'\n' ; }else cout<<str<<'\n' ; } signed main () { int T = 1 ; cin>>T; while (T--){ solve (); } return 0 ; }
题意 给出一个长度为n的数组a, 有 () , 请你给这个数组分为至少两组(每组之间的数都是连续的,所以相当于插入至少一个隔板来分组), 并且让每组的都是相同的。 如果不能分出至少两组,那么就输出 -1 。
一个数组的表示为 这个数组中没有出现过的最小的自然数 。如 。
思路 我们可以先找到整个数组的 ,我们称为, 这样一定可以分出一个子数组,使得他的 为 , 所以我们就看能否分出两组即可。我们从左到右开始收集数组中的元素, 如果收集到了全部的 这个数,由于我们已经知道整个数组中不含有,所以这个子数组的一定是,接下来我们再按此法不断收集,每当有完整的就分一组,最后看一下能否分出至少两组即可。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;void solve () { int n; cin>>n; vector<int > a (n+5 ) ; rep (i,1 ,n) cin>>a[i]; vector<int > cnt (n+5 ) ; rep (i,1 ,n) cnt[a[i]] ++; int mn = INF; if (cnt[0 ] == 0 ){ cout<<n<<'\n' ; rep (i,1 ,n) cout<<i<<' ' <<i<<'\n' ; return ; } int mex = 0 ; for (int i =0 ;i<=n;i++){ if (cnt[i] == 0 ){ mex = i; break ; } } int l = 1 ; vector<PII> ans; set<int > st; for (int i = 1 ;i<=n;i++){ if (a[i]<mex) st.insert (a[i]); if (st.size () == mex) { ans.push_back ({l,i}); st.clear ();l = i+1 ; } } if (ans.size () == 1 ) {cout<<-1 <<'\n' ;return ;} ans.back ().second = n; cout<<ans.size ()<<endl; for (auto p : ans){ cout<<p.first<<" " <<p.second<<'\n' ; } return ; } signed main () { int T = 1 ; cin>>T; while (T--){ solve (); } return 0 ; }
C. Messenger in MAC 题意 给出一个数组和数组, 我们可以从中取出一些数,这些数的总花费为如下公式:
现在问保证这个花费不大于l的情况下, 最多能选出**多少个数** 。
思路 不难发现,如果已经确定我们选择的数之后,那么第一项undefinedLarge \sum_{i=1}^{k} a_{p_i}\Large \sum_{i=1}^{k - 1} |b_{p_i} - b_{p_{i+1}}|MAX(b_{p_1},…,b_{p_k}) - MIN(b_{p_1},…,b_{p_k})bb$。
于是我们对数据按照b从小到大进行排序,我们选择出的一个数,就是他最右边数的b减去最左边数的b。
**思路一**:我们枚举左右端点,在确定左右端点后,我们只需要在这个区间中找到尽可能小的一些数,让他们相加小于 即可。
在枚举右端点的时候, 使用一个优先队列来维护”总值不超过“ ,于是就可以在 的复杂度内完成枚举所有的左右端点,每当更新一次区间, 就更新一次优先队列,当优先队列中的元素总和不满足要求时便可以快速地出队较大值的元素,从而保证优先队列中的总和满足条件的情况下,数尽可能少,数的数量尽可能多。
**思路二** : DP, 我们令表示为从i个数中我们选第一个数时视为 贡献了 ,中间的数可以当作背包来选择,每次枚举j时, 我们都试图将视为最后选择的一项来选出第项,这时候就要加 即要多算一个结尾贡献的, 所以我们判断 如果成立, 那么就代表这种情况下是可以选出 项的,于是
在枚举完j之后,我们让dp[i][1] = min(dp[i-1][1],a[i]-b[i]) , 表示在加入新的第项后,从这i项中选择1项最小是多少。
我们还要考虑只选择一个数的情况,即当 成立时,
最终输出ans即可。
代码 思路一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;struct Node { int a,b; friend bool operator <(Node n1,Node n2){ return n1. b < n2. b; } }; void solve () { int n,x; cin>>n>>x; vector<Node> vec (n+5 ) ; rep (i,1 ,n){ cin>>vec[i].a>>vec[i].b; } int ans = 0 ; sort (vec.begin ()+1 ,vec.begin ()+1 +n); for (int i = 1 ;i<=n;i++){ priority_queue<int > pq; int sum = 0 ; for (int j = i;j<=n;j++){ pq.push (vec[j].a);sum+=vec[j].a; while (pq.size () && vec[j].b-vec[i].b + sum > x){ sum -= pq.top (); pq.pop (); } ans = max (ans,(int )pq.size ()); } } cout<<ans<<endl; } signed main () { int T = 1 ; cin>>T; while (T--){ solve (); } return 0 ; }
**思路二**:jiangly的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <bits/stdc++.h> using i64 = long long ;constexpr i64 inf = 1E18 ;void solve () { int n, l; std::cin >> n >> l; std::vector<int > a (n) , b (n) ; for (int i = 0 ; i < n; i++) { std::cin >> a[i] >> b[i]; } int ans = 0 ; std::vector<int > p (n) ; std::iota (p.begin (), p.end (), 0 ); std::sort (p.begin (), p.end (), [&](int i, int j) { return b[i] < b[j]; }); std::vector<i64> dp (n + 1 , inf) ; for (auto i : p) { for (int j = n - 1 ; j >= 1 ; j--) { dp[j + 1 ] = std::min (dp[j + 1 ], dp[j] + a[i]); if (dp[j] + a[i] + b[i] <= l) { ans = std::max (ans, j + 1 ); } } dp[1 ] = std::min (dp[1 ], 1LL * a[i] - b[i]); if (a[i] <= l) { ans = std::max (ans, 1 ); } } std::cout << ans << "\n" ; } int main () { std::ios::sync_with_stdio (false ); std::cin.tie (nullptr ); int t; std::cin >> t; while (t--) { solve (); } return 0 ; }
D. Exam in MAC 题意 给出一个集合s 以及一个整数c , 问有多少对undefinedx,y), 0\le x \le y \le cx+yy-xs$中 。
思路 容斥题, 所有的undefinedx,y)\frac{(c+1)(c+2)}{2}x+y \in sy-x \in sx+y, y-x \in s$ 的数量即可。
先考虑 ,在我们选出一个 后, x可以在 中任选,这样总会有一个y,他可以保证 。即对于 的贡献为undefinedlfloor \frac{s_i}{2}\rfloor + 1$ 。
再考虑 , 我们选出一个数 后, y则可以在 中任选,这样总会有一个x,保证 。即对于 的贡献为 。
最后考虑对于undefinedx,y)x+y, y-xx+y = A, y-x = Bx = \frac{B-A}{2} , y = \frac{A+B}{2}A,Bodd, even\frac{odd(odd-1)}{2} + \frac{even(even-1)}{2}$
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <bits/stdc++.h> using namespace std;#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define int long long #define rep(i,l,r) for(int i = l;i<=r;i++) #define per(i,r,l) for(int i = r;i>=l;i--) const int INF = 0x3f3f3f3f3f3f3f3f ;typedef pair<int ,int > PII;void solve () { int n,c; cin>>n>>c; int ans = (c+1 )*(c+2 )/2 ; int odd ,even;odd = even = 0 ; for (int i = 1 ;i<=n;i++){ int num; cin>>num; ans -= num/2 + 1 ; ans -= (c - num + 1 ); if (num%2 ) odd ++; else even ++; } ans += odd*(odd+1 )/2 + even*(even+1 )/2 ; cout<<ans<<endl; } signed main () { int T = 1 ; cin>>T; while (T--){ solve (); } return 0 ; }