首先这样的问题第一个会想到有没有数学解,不过反正我是解不来的
这个范围很特殊,看到就应该有所考虑
暴搜?
2
81
\frak{2^{81}}
281肯定会炸。无效和重复计算的状态数太多了。
按行搜索?记录上一行的状态和剩下的
k
\frak{k}
k然后看看这一行能不能…?
记录上一行的状态显然可以状态压缩,
k
\frak{k}
k的话就多开一维…一维…
状压
d
p
\frak{dp}
dp。
注意预处理状态减小时间复杂度。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<queue>
#include<cctype>
using namespace std;
int N,K,Lim;
long long ans=0;
int L[1024]={};
int B[1024]={};
long long F[10][1024][90]={};
#ifdef test
void out(int x)
{
while(x)
{
cout<<(x&1);
x>>=1;
}
}
#endif
void pre(int step,int num,int cnt,bool cooldown)
{
if(step==N)
{
L[++L[0]]=num;
B[L[0]]=cnt;
return;
}
if(!cooldown)pre(step+1,num|(1<<step),cnt+1,1);
pre(step+1,num,cnt,0);
}
int main()
{
scanf("%d%d",&N,&K); Lim=(1<<N)-1;
pre(0,0,0,0);
#ifdef test
for(int i=1;i<=L[0];++i)out(L[i]),cout<<" "<<B[i]<<endl;
#endif
for(int i=1;i<=N;++i)
{
for(int j=1;j<=L[0];++j)
{
if(i==1)F[1][j][B[j]]=1;
else for(int k=1;k<=L[0];++k)
{
for(int g=B[k];g<=K-B[j];++g)
{
if((L[j]&L[k])||(L[j]&(L[k]>>1))||(L[j]&(L[k]<<1)))continue;
F[i][j][g+B[j]]+=F[i-1][k][g];
}
}
}
}
for(int i=1;i<=L[0];++i)ans+=F[N][i][K];
printf("%lld",ans);
return 0;
}