2017.8.15 [Haoi2016]字符合并 区间dp+状压dp
Posted A_LEAF
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017.8.15 [Haoi2016]字符合并 区间dp+状压dp相关的知识,希望对你有一定的参考价值。
【题目描述】
有一个长度为n的01串,你可以每次将相邻的k个字符合并,得到一个新的字符并获得一定分数。得到的新字符和分数由这k个字符确定。你需要求出你能获得的最大分数。
【输入格式】
第一行两个整数n,k。
接下来一行长度为n的01串,表示初始串。输入的的相邻字符之间用一个空格隔开。
接下来2k行,每行一个字符ci和一个整数wi,ci表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符, wi表示对应的第i种方案对应获得的分数。
【输出格式】
输出一个整数表示答案。
【样例输入】
3 2
1 0 1
1 10
1 10
0 20
1 30
【样例输出】
40
【样例说明】
第3行到第6行表示长度为2的4种01串合并方案。00->1,得10分,01->1得10分,10->0得20分,11->1得30分。
【数据范围】
对于100%的数据,n≥1,0≤i≤1,wi≥1
solution
考试compling error 原因是 int temp,; ...... 虽然编译过也只有15分,打的暴搜
正解是 区间dp+状压dp
f[i][j][k] i~j这个区间消到k状态时的最大得分 设 P为这个区间消到最后的长度
枚举Len(区间长度) l(左端点) r(右端点) mid(中间点,l~mid-1是最后消到长度为P-1,mid~r为 n(k-1)+1,因为这样mid~r正好可以消到长度为1) k ( 长度len-1的状态 )
mid要倒着枚举,如果P==len可以再用 f[i][j][0~(1<<k)-1] 更新 f[i][j][0]和f[i][j][1]
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #define ll long long 5 #define mem(a,b) memset(a,b,sizeof(a)) 6 using namespace std; 7 const int N=(1<<8)+50; 8 int read() 9 { 10 char q=getchar(); 11 while(q!=‘1‘&&q!=‘0‘)q=getchar(); 12 return q-‘0‘; 13 } 14 15 int n,k,maxp; 16 int u,o; 17 int a[306]; 18 ll f[306][306][N],c[N],w[N]; 19 ll g[2],ans; 20 21 int get(int l,int r) 22 { 23 int temp=0; 24 for(int i=l;i<=r;++i) 25 temp|=(a[i]<<(r-i)); 26 return temp; 27 } 28 29 int main(){ 30 31 //freopen("merge.in","r",stdin); 32 //freopen("merge.out","w",stdout); 33 34 scanf("%d%d",&n,&k); 35 for(int i=1;i<=n;++i) 36 a[i]=read(); 37 maxp=(1<<k)-1; 38 for(int i=0;i<=maxp;++i) 39 scanf("%lld%lld",&c[i],&w[i]); 40 41 mem(f,-60); 42 int qqq=f[0][0][0]; 43 for(int i=1;i<=n;++i) 44 f[i][i][a[i]]=0; 45 46 for(int l=2;l<=n;++l) 47 { 48 int q1=n-l+1; 49 for(int i=1;i<=q1;++i) 50 { 51 int j=i+l-1; 52 int len=j-i; 53 while(len>=k) 54 len-=(k-1);//在求合并之后的长度 55 56 for(int d=j;d>=i;d-=(k-1)) 57 for(int p=0;p<(1<<len);++p) 58 if(f[i][d-1][p]!=qqq) 59 { 60 if(f[d][j][0]!=qqq) 61 f[i][j][p<<1]=max(f[i][j][p<<1],f[i][d-1][p]+f[d][j][0]);//枚举右边是 nk+(k-1),这样整k个的合并 62 if(f[d][j][1]!=qqq) 63 f[i][j][p<<1|1]=max(f[i][j][p<<1|1],f[i][d-1][p]+f[d][j][1]); 64 } 65 66 if(len==k-1) 67 { 68 g[0]=f[i][j][0]; 69 g[1]=f[i][j][1]; 70 71 for(int p=0;p<=maxp;++p) 72 if(f[i][j][p]!=qqq) 73 g[c[p]]=max(g[c[p]],f[i][j][p]+w[p]); 74 75 f[i][j][0]=g[0]; 76 f[i][j][1]=g[1]; 77 } 78 79 } 80 } 81 82 for(int i=0;i<=maxp;++i) 83 ans=max(ans,f[1][n][i]); 84 cout<<ans; 85 //while(1); 86 return 0; 87 }
以上是关于2017.8.15 [Haoi2016]字符合并 区间dp+状压dp的主要内容,如果未能解决你的问题,请参考以下文章