洛谷传送门
CF传送门
解题思路
先想O(n^2)暴力,第一层循环为序列a1的最终长度i,第二层循环为序列a3的最终长度j,那么操作次数为原序列a1给a2和a3的数字个数+a2给a1a3的个数+a3给a1a2的个数。
可以预处理出三个数组,cnt1[i]表示序列a1中1……i中有几个数字,cnt2[i]表示序列a2中n-i+1……n中有几个数字,cnt3[i]表示序列a3中n-i+1……n中有几个数字。
可以大致理解为cnt1为前缀,cnt2、3为后缀。
所以对于每一个循环的i、j,ans=(k1-cnt1[i])+(k2-cnt2[n-i]+cnt2[j])+(k3-cnt3[j])。
整理一下,为ans=k1+k2+k3-cnt1[i]-cnt2[n-i]+cnt2[j]-cnt3[j]=n-cnt1[i]-cnt2[n-i]+(cnt2[j]-cnt3[j])。
我们可以发现,i和j并没有直接对答案造成相关联的影响,所以我们就可以预处理出cnt2[j]-cnt3[j]的最小值。
注意j的范围为0~n-i。
再预处理一个数组d[i]=cnt2[i]-cnt3[i],minn[i]=min(d[1]……d[i])。
所以最终ans=n-cnt1[i]-cnt2[n-i]+minn[n-i]。
O(nlogn)(需要排序)。
AC代码
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<iomanip> 5 #include<cmath> 6 #include<algorithm> 7 using namespace std; 8 const int maxn=200005; 9 int k1,k2,k3,n,a[maxn],b[maxn],c[maxn],d[maxn],minn[maxn],ans=100000005; 10 int cnt1[maxn],cnt2[maxn],cnt3[maxn]; 11 int main(){ 12 cin>>k1>>k2>>k3; 13 n=k1+k2+k3; 14 for(int i=1;i<=k1;i++) cin>>a[i]; 15 for(int i=1;i<=k2;i++) cin>>b[i]; 16 for(int i=1;i<=k3;i++) cin>>c[i]; 17 sort(a+1,a+k1+1); 18 sort(b+1,b+k2+1); 19 sort(c+1,c+k3+1); 20 int cnt=1; 21 for(int i=1;i<=n;i++){ 22 cnt1[i]=cnt1[i-1]; 23 if(a[cnt]==i) cnt1[i]++,cnt++; 24 } 25 cnt=k2; 26 for(int i=1;i<=n;i++){ 27 cnt2[i]=cnt2[i-1]; 28 if(b[cnt]==n-i+1) cnt2[i]++,cnt--; 29 } 30 cnt=k3; 31 for(int i=1;i<=n;i++){ 32 cnt3[i]=cnt3[i-1]; 33 if(c[cnt]==n-i+1) cnt3[i]++,cnt--; 34 } 35 for(int i=1;i<=n;i++) d[i]=cnt2[i]-cnt3[i]; 36 for(int i=1;i<=n;i++) minn[i]=min(minn[i-1],d[i]); 37 for(int i=0;i<=n;i++){ 38 ans=min(ans,n-cnt1[i]-cnt2[n-i]+minn[n-i]); 39 } 40 cout<<ans<<endl; 41 return 0; 42 }