原题地址
题解
算法复杂度 \(O(2^{n}*len*log_2(len))\)
dp[i][S]
表示在第 \(i\) 个数后状态为 \(S\) 的时候的方案数.num[i][j]
表示 \(i\) 到 \(j\) 组成的数字.
①首先预处理出 num[i][j]
根据 \(len<=75\) 得出 \(max<=20\)
\(len_{max}<=5\) 所以 \(j-i<=5\);
②通过 \(len\) 计算出 \(n\)
③状态转移方程
\[dp[j][S|(1<<num[i][j]-1)+=dp[i][S];\]
④初值为dp[i][0]=1
其中 \(i\) 为 \(1 \to n-1\)
⑤计算 bin[]
数组
\(bin[i]=2^i-1\)
⑥\[ans=\sum_{j=0}^n dp[bin[i]][j]\]
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=80,mod=1e9+7;
int n;
int x[maxn],num[maxn][maxn],limit=0;
int dp[76][(1<<20)+5];
int bin[22];
void readn()
{
getchar();
for(int i=1;i<=n;i++)
x[i]=getchar()-'0';
}
void get_01()
{
for(register int i=0;i<=n-1;i++)
for(register int j=i+1;j<=n;j++)
{
int temp=1;
for(register int k=j;k>=i+1;k--)
{
num[i][j]+=x[k]*temp;
temp*=2;
if(num[i][j]>22)
break;
}
}
}
int main()
{
int temp=2;
for(int i=1;i<=21;i++)
{
bin[i]=temp-1;
temp=temp*2;
}
limit=20;
scanf("%d",&n);
readn();
get_01();
for(register int i=0;i<=n;i++)dp[i][0]=1;
for(register int j=0;j<=n-1;j++)
for(register int i=0;i<=(1<<limit)-1;i++)
{
if(!dp[j][i]) continue;
for(register int k=j+1;k<=n;k++)
{
if(num[j][k]>limit)break;
if(num[j][k]==0)continue;
dp[k][i|(1<<num[j][k]-1)]=(dp[k][i|(1<<num[j][k]-1)]+dp[j][i])%mod;
}
}
int sum=0;
for(register int i=1;bin[i]<=(1<<limit)-1;i++)
for(register int j=0;j<=n;j++)
{
sum+=dp[j][bin[i]];
sum%=mod;
}
printf("%d\n",sum);
}