题目链接
Problem 2204 7
做法:如果不考虑环的话,可以想到简单dp:dp[i][j][k] 当前位置i 放k 且已经有连续的j个k时的方案数。
首位放1 和 首位放0 是一样的,所以考虑一半,答案最后乘2就可以了。
考虑首位放0。由于是成环的,所以统计答案的时候枚举后缀是连续的j个1时的方案数就可以了。
这时候疑问来了:那这个方案统计了吗?
dp[n][5][0]
01****100000由于会有不合法计算:
001**100000
其实已经计算的了:
下面的状态就是计算过的:
dp[n-1][5][0]01****100001
包含了
01****100000上面两个均可由下面这个转移
01****10000
/*
dp[n][5][0]
01****100000
//不合法计算:001**100000
下面的计算方法:
dp[n-1][5][0]
01****100001
包含了
01****100000
上面两个均可由下面这个转移
01****10000
*/
#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int mod=2015;
const int N=1e5+10;
int dp[N][7][2],n;
//ÄÐ1
void add(int &x,int y)
{
x=(x+y)%mod;
}
int main()
{
int cas=0;
dp[1][1][0]=1;
for(int i=2;i<=100000;++i){
for(int j=1;j<=6;++j){
add(dp[i][j][1],dp[i-1][j-1][1]);
add(dp[i][j][0],dp[i-1][j-1][0]);
add(dp[i][1][1],dp[i-1][j][0]);
add(dp[i][1][0],dp[i-1][j][1]);
}
}
int _=read();while(_--)
{
n=read();
printf("Case #%d: ",++cas);
if(n<=6){printf("%d\n",1<<n);continue;}
int ans = 0;
for(int i = 1; i <= 6; ++i) {
for(int j = 1; j <= n - i && j < 7; ++j) {
add(ans,dp[n-i][j][0]);
if(i+j>=7) continue;//i+1 到n 均是1 n-(n-i) =i 个1
add(ans,dp[n-i][j][1]);
}
}
add(ans, ans);
printf("%d\n", ans);
}
}