题目大意:给你一个序列,让你提取出一个子序列A,剩余的部分组成子序列B,现定义seg(x)表示把序列x中相邻的相同数合并成一个数后,序列x的长度,分别求seg(A)+seg(B)的最大值和最小值,n=1e5
考场上并没有想出最小值做法,只会最大值的贪心,下考才知道可以DP做??
最大值的贪心:
维护$nxt[i]$表示$a[i]$下一次出现的位置。再模拟构造两个序列的过程,新加进来的数放在序列尾元素的$nxt$较小的序列
1 #include <cmath> 2 #include <queue> 3 #include <vector> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #define ll long long 8 #define ull unsigned long long 9 #define dd double 10 using namespace std; 11 const int N1=105; const ll inf=0x3f3f3f3f3f3f3f3fll; 12 13 int n; 14 int a[N1],b[N1],c[N1],nxt[N1],la[N1],cntb,cntc; 15 16 int main() 17 { 18 scanf("%d",&n); 19 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 20 int i,j,ans=0; 21 for(i=n;i>=1;i--) 22 { 23 if(!la[a[i]]) la[a[i]]=i, nxt[i]=n+1; 24 else nxt[i]=la[a[i]], la[a[i]]=i; 25 } 26 nxt[0]=n+1; 27 for(i=1;i<=n;i++) 28 { 29 if(a[i]==a[b[cntb]]&&a[i]==a[c[cntc]]){ 30 if(b[cntb]>c[cntc]) c[cntc]=i; 31 else b[cntb]=i; 32 }else if(a[i]==a[b[cntb]]){ 33 c[++cntc]=i; 34 }else if(a[i]==a[c[cntc]]){ 35 b[++cntb]=i; 36 }else{ 37 if(a[b[cntb]]==a[c[cntc]]){ 38 if(b[cntb]>c[cntc]) c[++cntc]=i; //改小的 39 else b[++cntb]=i; 40 }else{ 41 if(nxt[b[cntb]]<=nxt[c[cntc]]) b[++cntb]=i; 42 else c[++cntc]=i; 43 } 44 } 45 } 46 printf("%d\n",cntb+cntc); 47 return 0; 48 }View Code
最小值的DP:
首先一步贪心,把相邻的相同元素都合并,这样新的序列里一定没有相同的相邻元素
题目里把序列划分成$01$序列,我们$DP$每个01or10分界点!
维护$f[i][0/1]$表示第$i$个元素放在$0/1$,第$i-1$个元素放在$1/0$时的答案
也就是$j~i-1$的元素放在一个序列里,再把$i$接在$j-1$所在序列的后面
可得方程$f[i][0/1]=f[j][1/0]+i-j-(a[i]=a[j-1])$
利用前缀和优化成$O(n)$
1 #include <cmath> 2 #include <queue> 3 #include <vector> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #define ll long long 8 #define ull unsigned long long 9 #define dd double 10 using namespace std; 11 const int N1=100005; const int inf=0x3f3f3f3f; 12 13 int n,nn; 14 int a[N1],b[N1],f[N1][2],mval[N1][2]; 15 16 int main() 17 { 18 scanf("%d",&nn); 19 for(int i=1;i<=nn;i++) scanf("%d",&b[i]); 20 for(int i=1;i<=nn;i++) if(b[i]!=b[i-1]) a[++n]=b[i]; 21 memset(mval,0x3f,sizeof(mval)); a[0]=-1; 22 // mi[1][0]=f[1][0]=1; 23 f[1][0]=1; f[1][1]=inf; 24 int mf[2]={0,inf}; 25 for(int i=2;i<=n;i++) 26 { 27 f[i][0]=min(mval[a[i]][1]+i-1,mf[1]+i); 28 f[i][1]=min(mval[a[i]][0]+i-1,mf[0]+i); 29 mf[0]=min(f[i][0]-i,mf[0]); mf[1]=min(f[i][1]-i,mf[1]); 30 mval[a[i-1]][0]=min(mval[a[i-1]][0],f[i][0]-i); 31 mval[a[i-1]][1]=min(mval[a[i-1]][1],f[i][1]-i); 32 } 33 printf("%d\n",min(f[n][0],f[n][1])); 34 return 0; 35 }View Code