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 }

code

时间: 2024-10-25 02:49:34

2017.8.15 [Haoi2016]字符合并 区间dp+状压dp的相关文章

『字符合并 区间dp 状压dp』

字符合并 Description 有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数.得到的新字符和分数由这 k 个字符确定.你需要求出你能获得的最大分数. Input Format 第一行两个整数n,k.接下来一行长度为n的01串,表示初始串. 接下来2^k行,每行一个字符ci和一个整数wi,ci表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符,wi表示对应的第i种方案对应获得的分数. 1<=n<=300,0<

CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高位数字不为0. 因此,符合我们定义的最小的有趣的数是2013.除此以外,4位的有趣的数还有两个:2031和2301. 请计算恰好有n位的有趣的数的个数.由于答案可能非常大,只需要输出答案除以1000000007的余数. 输入格式 输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000). 输

HDU 1074 Doing Homework DP 状压DP

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1074 题目描述: 给你所有课程的截止时间和工作时长, 一次只能做一种作业, 问最少罚时几天 N <= 15 解题思路: 由于N很小, 所以第一反应就是状压DP, 我们可以用一个15位二进制数来表示各个课程做完还是没做完, 然后从 S 从 1 到 1 << N 枚举 i 从 1 到 N 枚举, 如果S & (1<<i) 有效则说明i 属于情况 S, 这样我们从上一步S -

[转]状态压缩dp(状压dp)

状态压缩动态规划(简称状压dp)是另一类非常典型的动态规划,通常使用在NP问题的小规模求解中,虽然是指数级别的复杂度,但速度比搜索快,其思想非常值得借鉴. 为了更好的理解状压dp,首先介绍位运算相关的知识. 1.'&'符号,x&y,会将两个十进制数在二进制下进行与运算,然后返回其十进制下的值.例如3(11)&2(10)=2(10). 2.'|'符号,x|y,会将两个十进制数在二进制下进行或运算,然后返回其十进制下的值.例如3(11)|2(10)=3(11). 3.'^'符号,x^y

bzoj1076: [SCOI2008]奖励关(期望dp+状压dp)

1076: [SCOI2008]奖励关 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2989  Solved: 1557[Submit][Status][Discuss] Description 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不吃(必须在抛出下一个宝物之前做出选择,且现在决定不吃的宝物以后也不能再吃). 宝物一共有n种,系统每次抛出这n种宝物的概率都相同且相

SCUT - 254 - 欧洲爆破 - 概率dp - 状压dp

https://scut.online/p/254 思路很清晰,写起来很恶心. #include<bits/stdc++.h> using namespace std; #define ll long long int dp[1<<20]; //dp[k] 从状态k开始直到k=0还需要的期望次数 0表示炸弹已爆炸,1表示炸弹未爆炸 int x[20]; int y[20]; int r[20]; int pa[20]; ll n; ll invn; int all1; int vi

HDU 1074 Doing Homework(状压DP)

Problem Description Ignatius has just come back school from the 30th ACM/ICPC. Now he has a lot of homework to do. Every teacher gives him a deadline of handing in the homework. If Ignatius hands in the homework after the deadline, the teacher will r

【状压DP】【HDOJ1074】

http://acm.hdu.edu.cn/showproblem.php?pid=1074 Doing Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 12269    Accepted Submission(s): 5911 Problem Description Ignatius has just come bac

状压dp,区间dp,矩阵快速幂

DP 首先先回忆一下dp,dp叫做记忆化搜索,是一种可以把暴力搜索中重复的部分重复利用,从而到达减小复杂度的目的.比如最应该熟悉的背包模型,如果你把选择的过程看成一步一步的,那么在这么多的搜索路径中一定有着很多很多的重复部分,dp就是一种把重复的部分加以利用的方法.相信大家都已经在以前的练习中已经明白了dp是什么样的思路了,接下来的两种dp会在大家已经了解经典的背包dp等模型下展开. 状态压缩dp: 首先先讲一个状压dp最最经典的模型,求哈密尔顿路径问题,也叫做旅行商问题:给你一张图,你要在每个