題目大意:給你一個序列,讓你提取出一個子序列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 }
最小值的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 }