CF1479B Painting the Array(贪心+DP)

题目大意:给你一个序列,让你提取出一个子序列A,剩余的部分组成子序列B,现定义seg(x)表示把序列x中相邻的相同数合并成一个数后,序列x的长度,分别求seg(A)+seg(B)的最大值和最小值,n=1e5

考场上并没有想出最小值做法,只会最大值的贪心,下考才知道可以DP做??

 

最大值的贪心:

维护$nxt[i]$表示$a[i]$下一次出现的位置。再模拟构造两个序列的过程,新加进来的数放在序列尾元素的$nxt$较小的序列

CF1479B Painting the Array(贪心+DP)
 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)$

CF1479B Painting the Array(贪心+DP)
 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

 

上一篇:[CF1479B1/CF1480D1] Painting the Array I


下一篇:tile painting