习题:Felicity's Big Secret Revealed(状压DP)
题目
思路
经过打表可以发现,出现的最大值最大只能为20,
我们设\(dp[i][j]\)表示最后一刀切在i和i+1之间,已经有的状态为j
转移的话暴力枚举接下来的一个区间即可
考虑到要舍去第一刀前面的内容,所以对于所有的\(dp[i][0]\)都要赋上1的初值
最后的答案即为\(\sum_{i=1}^{n}\sum_{j=1}^{20}dp[i][j]\)
代码
#include<iostream>
using namespace std;
const int mod=1e9+7;
int dp[76][(1<<20)],ans;
int n;
int a[76];
char s[76];
void divide(int val)
{
if(val==0)
cout<<'0';
while(val)
{
cout<<(val&1);
val>>=1;
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
cin>>(s+1);
for(int i=1;i<=n;i++)
{
a[i]=s[i]-'0';
dp[i][0]=1;
}
dp[0][0]=1;
for(int i=0;i<=n;i++)
{
for(int j=0;j<(1<<20);j++)
{
int now=0;
for(int k=i+1;k<=n;k++)
{
now=(now<<1)+a[k];
if(now==0)
continue;
if(now>20)
break;
dp[k][j|(1<<(now-1))]=(dp[k][j|(1<<(now-1))]+dp[i][j])%mod;
}
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=20;j++)
ans=(ans+dp[i][(1<<j)-1])%mod;
cout<<ans;
return 0;
}

浙公网安备 33010602011771号