FZU 2204(环形dp)

题目链接

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);

    }
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/106382438