zoukankan      html  css  js  c++  java
  • 2017.8.15 [Haoi2016]字符合并 区间dp+状压dp

    【题目描述】

    有一个长度为n01串,你可以每次将相邻的k个字符合并,得到一个新的字符并获得一定分数。得到的新字符和分数由这k个字符确定。你需要求出你能获得的最大分数。

    【输入格式】

    第一行两个整数n,k

    接下来一行长度为n01串,表示初始串。输入的的相邻字符之间用一个空格隔开。

    接下来2k行,每行一个字符ci和一个整数wici表示长度为k01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符, wi表示对应的第i种方案对应获得的分数。

    【输出格式】

    输出一个整数表示答案。

    【样例输入】

    3 2
    1 0 1
    1 10
    1 10
    0 20
    1 30
    

    【样例输出】

    40

    【样例说明】

    第3行到第6行表示长度为2401串合并方案。00->1,得10分,01->110分,10->020分,11->130分。

    【数据范围】

    对于100%的数据,n1,0i1,wi1

    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 }
    code
  • 相关阅读:
    LCA算法总结
    【福利】论机房如何关闭方正软件保护卡
    codevs 2190 有理逼近
    用C语言的rand()和srand()产生伪随机数的方法总结
    float,double等精度丢失问题 float,double内存表示
    #incldue<cctype>函数系列
    poj 2348 Euclid's Game 题解
    poj 2240 Arbitrage 题解
    洛谷 p1352 没有上司的舞会 题解
    BZOJ 1093 最大半连通子图 题解
  • 原文地址:https://www.cnblogs.com/A-LEAF/p/7366884.html
Copyright © 2011-2022 走看看