CF757D Felicity‘s Big Secret Revealed

一、题目

点此看题

二、解法

n 75 n\leq75 非常灵性,转化一下数据范围, i = 1 21 p o p c o u n t ( i ) = 78 \sum_{i=1}^{21}popcount(i)=78 ,这说明最大的数只可能有 20 20 ,提示我们可以状压。

d p [ i ] [ s ] dp[i][s] 为最后一次切割到 i 1 i-1 位,切割出来的数状态压缩为 s s 的方案数,由于最前面的一段可以舍去,把所有 d p [ i ] [ 0 ] = 1 ( 1 i n ) dp[i][0]=1(1\leq i\leq n) ,注意一下转移过程中不能出现数字 0 0 ,最后一段可以舍去的条件就通过枚举所有终点的方式来解决。

#include <cstdio>
const int M = 80;
const int MOD = 1e9+7;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,ans,a[M],dp[M][1<<20];
signed main()
{
	n=read();
	for(int i=1;i<=n;i++) scanf("%1d",&a[i]);
	for(int i=1;i<=n;i++)
	{
		dp[i][0]=1;
		for(int k=0;k<(1<<20);k++)
			for(int j=i,p=a[i];j<=n&&p<=20;j++,p=(2*p+a[j]))
				if(p) dp[j+1][k|(1<<p-1)]=(dp[j+1][k|(1<<p-1)]+dp[i][k])%MOD;
	}
	for(int i=1;i<=n+1;i++)
		for(int j=1;j<=20;j++)
			ans=(ans+dp[i][(1<<j)-1])%MOD;
	printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/107884744