CF1257E The Contest(预处理优化)

洛谷传送门

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 }
原文地址:https://www.cnblogs.com/yinyuqin/p/14426028.html