/*
d[n][i][j] 表示字符长度为n时,范围在i到j之间的字符串个数。
范围的计算:范围就是从第n个字符开始往前推1比0多的个数,i代表最小值,j代表最大值;
因为下标不能是负数所以处理的时候用5来表示0;
比如 01011的范围就是0到2;
刚开始范围是 0到0
1 的范围是0到1
11 的范围是0到2
011 的范围是0到2
1011 的范围是0到2
01011 的范围是0到2
先把k位的字符串预处理,然后就是递推了。
递推的时候就是在前一个字符串后面加1或0;
d[n+1][i-1][j-1]+=d[n][i][j];
d[n+1][i+1][j+1]+=d[n][i][j];
边界要特殊处理一下详情看代码吧;
*/
#include <stdio.h>
#include <string.h>
__int64 max(__int64 a,__int64 b)
{
if(a>b) return a;
else return b;
}
__int64 min(__int64 a,__int64 b)
{
if(a<b) return a;
else return b;
}
__int64 d[70][20][20],n,k;
void dp()
{
__int64 mi,ma,l;
for(int i=0;i<(1<<k);i++)
{
mi=ma=l=5;
for(int j=1;j<(1<<k);j*=2)
{
if(i&j) l++;
else l--;
ma=max(ma,l);
mi=min(mi,l);
}
d[k][mi][ma]++;
}
for(int i=k;i<n;i++)
{
d[i+1][6-k][6]+=d[i][5-k][5]; //d[i][5-k][5]后面只能加1,加0的话下界就是4-k
//也就是-(k+1)因为题目要求-k到k所以-(k+1)就没必要算了
d[i+1][4][4+k]+=d[i][5][5+k];
for(int j=6-k;j<=5;j++)
for(int l=5;l<=4+k;l++)
{
d[i+1][min(j+1,5)][l+1]+=d[i][j][l];
d[i+1][j-1][max(l-1,5)]+=d[i][j][l];
}
}
}
int main()
{
__int64 sum;
while(scanf("%I64d%I64d",&n,&k)!=-1)
{
if(n<=k) k=n;
memset(d,0,sizeof(d));
dp();
sum=0;
for(int i=5-k;i<=5;i++)
for(int j=5;j<=5+k;j++)
sum+=d[n][i][j];
printf("%I64d\n",sum);
}
return 0;
}
1545 01-K Code
最新推荐文章于 2020-07-26 18:01:54 发布