题意
三我的,每一个人有一些数字,组合起来是\(1\)-\(n\),每一个人能够给另外一我的一个拥有的数字,问最小操做数,使得第一我的拥有\(1\)-\(i\)的数,第二我的拥有\(i+1\)-\(j\)的数,第三我的拥有\(j+1\)~\(n\)的数,即第一我的为前缀,第二我的为中间部分,第三我的为后缀。
注意:能够有一个或两我的最后不拥有数字。ios
分析
看到三我的操做,咱们先看两我的操做时的状况:
假设到最后,第一我的拥有\(1\)-\(i\),第二我的拥有\(i+1\)-\(n\),那么最小操做数为第二我的\(1\)-\(i\)中拥有的数字加上第一我的\(i+1\)-\(n\)中拥有的数字。咱们能够采用前缀和,\(cnt1[k]\)表示第一我的前\(k\)个数中拥有的个数,\(cnt2[k]\)表示第二我的前\(k\)个数中拥有的个数,则表达式为:$$cnt2[i]+cnt1[n]-cnt1[i]$$受到启发咱们看三我的操做时的状况:
假设到最后,第一我的拥有\(1\)-\(i\),第二我的拥有\(i+1\)~\(j\),第三我的拥有\(j+1\)-\(n\),那么最小操做数为第二我的和第三我的\(1\)-\(i\)中拥有的个数加上第一我的和第三我的\(i+1\)-\(j\)中拥有的个数加上第一我的和第二我的\(j+1\)-\(n\)中拥有的个数。咱们能够采用前缀和,\(cnt1[k]\)表示第一我的前\(k\)个数中拥有的个数,\(cnt2[k]\)表示第二我的前\(k\)个数中拥有的个数,\(cnt3[k]\)表示第三我的前\(k\)个数中拥有的个数字表达式为:$$cnt2[i]+cnt3[i]+cnt1[j]-cnt1[i]+cnt3[j]-cnt3[i]+cnt1[n]-cnt1[j]+cnt2[n]-cnt2[j]$$化简获得:$$cnt2[i]-cnt1[i]+cnt3[j]-cnt2[j]+cnt1[n]+cnt2[n]$$咱们从\(0\)-\(n\)枚举\(i\),接下来咱们考虑\(j\)的取值,咱们能够看到对于固定的\(i\),只须要找到一个\(j\)使得该式子最小便可,那么咱们能够设置一个后缀\(minn[]\)数组,\(minn[i]\)表示当\(i\leq j\leq n\)时,\(cnt3[j]-cnt2[j]\)最小的值,那么答案即为:$$cnt2[i]-cnt1[i]+minn[i]+cnt1[n]+cnt2[n]$$
代码c++
#pragma GCC optimize(3, "Ofast", "inline") #include <bits/stdc++.h> #define start ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define ll long long #define LL long long using namespace std; const int maxn = (ll) 2e5 + 5; const int mod = 1000000007; const int inf = 0x3f3f3f3f; int cnt1[maxn], cnt2[maxn], cnt3[maxn]; int minn[maxn]; vector<int> v1, v2, v3; int main() { start; int k1, k2, k3; cin >> k1 >> k2 >> k3; v1.resize(k1 + 5); v2.resize(k2 + 5); v3.resize(k3 + 5); /*输入并标记*/ for (int i = 1; i <= k1; ++i) { cin >> v1[i]; ++cnt1[v1[i]]; } for (int i = 1; i <= k2; ++i) { cin >> v2[i]; ++cnt2[v2[i]]; } for (int i = 1; i <= k3; ++i) { cin >> v3[i]; ++cnt3[v3[i]]; } int n = k1 + k2 + k3; for (int i = 1; i <= n; ++i) {//前缀和 cnt1[i] = cnt1[i - 1] + cnt1[i]; cnt2[i] = cnt2[i - 1] + cnt2[i]; cnt3[i] = cnt3[i - 1] + cnt3[i]; } /*如分析*/ for (int i = 0; i <= n; ++i) minn[i] = cnt3[i] - cnt2[i]; for (int i = n - 1; i >= 0; --i) minn[i] = min(minn[i + 1], minn[i]); int ans = inf; for (int i = 0; i <= n; ++i) { int t = cnt2[i] - cnt1[i] + minn[i] + cnt1[n] + cnt2[n]; ans = min(ans, t); } cout << ans; return 0; }
本场比赛\(D\)和\(E\)惨痛教训:玩后缀必定要注意边界!!!
如有问题可在评论区提出,谢谢。数组