一、题目
二、解法
n ≤ 75 n\leq75 n≤75非常灵性,转化一下数据范围, ∑ i = 1 21 p o p c o u n t ( i ) = 78 \sum_{i=1}^{21}popcount(i)=78 ∑i=121popcount(i)=78,这说明最大的数只可能有 20 20 20,提示我们可以状压。
设 d p [ i ] [ s ] dp[i][s] dp[i][s]为最后一次切割到 i − 1 i-1 i−1位,切割出来的数状态压缩为 s s s的方案数,由于最前面的一段可以舍去,把所有 d p [ i ] [ 0 ] = 1 ( 1 ≤ i ≤ n ) dp[i][0]=1(1\leq i\leq n) dp[i][0]=1(1≤i≤n),注意一下转移过程中不能出现数字 0 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);
}