fzu2204 dp

时间:2022-02-21 00:09:17

2015-10-06 19:31:05


n个有标号的球围成一个圈。每个球有两种颜色可以选择黑或白染色。问有多少种方案使得没有出现连续白球7个或连续黑球7个。

每组包含n,表示球的个数。(1 <= n <= 100000)

dp[i][0][x] 表示在第i为填黑色且加上第i位连续的前面有x个黑色的球,dp[i][1][x]表示在第i为填白色且加上第i位连续的前面有x个白色的球

我们只算第一个球为白色,那么最后计算出的个数会等于第一个球去黑色的个数,这个很好理解,只要把他们的颜色相对应的反转一下就好了。然后剩下的好了,

最后的答案 是 dp[n][0-1][1-6] 再减去一些首位连接会超过7个的方案就好了,枚举前几位分别放什么相同的颜色,然后后面减去就好了

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
using namespace std;
const int maxn=;
const int mod=;
int dp[maxn][][];
int solve(int n){
int ans=;
for(int i=;i<(<<n); i++)
{
int hei=,bai=;
int bo=;
for(int j=; j<n; j++){
hei=;bai=;
for(int k=; k<;k++)
if( ( <<((j+k)%n) ) & i )bai++;
else hei++;
if(hei>=||bai>=){
bo=;break;
}
}
if(bo)ans++;
}
return ans%mod;
}
int solve2(int n)
{
int ans=;
for(int i=; i>=; i--)
{
ans=(ans+dp[n][][i]+dp[n][][i])%mod;
}
ans=(ans*)%mod;
for(int i=; i<; i++)
{
for(int j=-i; j<=; j++)
{
ans=(ans-(dp[n-i][][j]+dp[n-i][][j])%mod+mod)%mod;
}
}
return ans;
}
int main()
{
memset(dp,,sizeof(dp));
dp[][][]=;
for(int i=; i<=; i++)
{
for(int j=;j<=;j++)
dp[i][][]=(dp[i-][][j]+dp[i][][])%mod;
for(int k=; k<=; k++)
dp[i][][k]=dp[i-][][k-];
for(int j=; j<=;j++)
dp[i][][]=(dp[i-][][j]+dp[i][][])%mod;
for(int k=; k<=; k++)
dp[i][][k]=dp[i-][][k-];
}
int n;
int cas;
scanf("%d",&cas);
for(int cc=; cc<=cas; cc++)
{
scanf("%d",&n);
if(n<)
{
printf("Case #%d: %d\n",cc,<<n);
}
else if(n<=){
int ans=solve(n);
printf("Case #%d: %d\n",cc,ans);
}else{int d=solve2(n);
printf("Case #%d: %d\n",cc,d);
}
}
return ;
}