FZUOJ Problem 2200 cleaning DP

Problem 2200 cleaning

 

 

 Problem Description

N个人围成一圈在讨论大扫除的事情,需要选出K个人。但是每个人与他距离为2的人存在矛盾,所以这K个人中任意两个人的距离不能为2,他们想知道共有多少种方法。

 Input

第一行包含一个数T(T<=100),表示测试数据的个数。

接下来每行有两个数N,K,N表示人数,K表示需要的人数(1<=N<=1000,1<=K<=N)。

 Output

输出满足题意的方案数,方案数很大,所以请输出方案数mod 1,000,000,007 后的结果。

 Sample Input

2 4 2 8 3

 Sample Output

4 16

 Source

FOJ有奖月赛-2015年10月
 
 
题解:
  设定 f[k][h] [i][j] 表示在不考虑环的清形下第一,二位置上的选择状态为k,h下,前i个选了j个人的方案数
    dp[k][h][i][j], 表示在考虑环的清形下第一,二位置上的选择状态为k,h下,前i个选了j个人的方案数
  那么对于f数组的递推,当前第i位置选与不选,i-1位置选与不选有
        f[k][h] = f[k][h][ii-1][j] +f[k][h][i-3][j-1] + f[k][h][i-4][j-2];
  对于dp数组转移同理就是拿f数组来更新
  具体看代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 1e3+20, M = 1e6+10, mod = 1e9+7,inf = 2e9;

void update(int x,int& y) {
    y += x;
    if(y > mod) y -= mod;
}
int T,dp[2][2][N][N],f[2][2][N][N];//前i个人选j人,前两人状态
void init() {
    dp[0][0][0][0] = 1;
    dp[0][0][1][0] = 1;
    dp[1][0][1][1] = 1;
    dp[0][0][2][0] = 1;
    dp[1][0][2][1] = 1;
    dp[0][1][2][1] = 1;
    dp[1][1][2][2] = 1;

    dp[0][0][3][0] = 1;

    dp[0][0][3][1] = 1;
    dp[0][1][3][1] = 1;
    dp[1][0][3][1] = 1;

    dp[1][1][3][2] = 1;
    dp[1][0][3][2] = 1;
    dp[0][1][3][2] = 1;

    dp[1][1][3][3] = 1;





    for(int i = 0; i < 2; ++i) {
        for(int j = 0; j < 2; ++j) {
            for(int k = 0; k <= 3; ++k) {
                for(int h = 0; h <= k; ++h)
                    f[i][j][k][h] = dp[i][j][k][h];
            }
        }
    }
    f[1][1][3][3] = 0;
    f[1][0][3][2] = 0;
    for(int k = 0; k < 2; ++k) {
        for(int h = 0; h < 2; ++h) {
            for(int i = 4; i <= 1000; ++i) {
                for(int j = 0; j <= i; ++j) {
                //不选, i-1选
                if(i >= 5) {
                    if(!k && j >= 1) update(f[k][h][i-4][j-1],dp[k][h][i][j]);
                 if(!k && j >= 2)
                    if(i >= 5)update(f[k][h][i-5][j-2],dp[k][h][i][j]);
                }
                else {
                     if(!k && j >= 1) update(f[k][h][i-2][j-1],dp[k][h][i][j]);
                }

                //i不选,i-1不选
                update(f[k][h][i-2][j],dp[k][h][i][j]);
                //i位置选,i-1不选
                if(!h&&j>=1)update(f[k][h][i-3][j-1],dp[k][h][i][j]);


                 //i位置选,i-1选
                 if(!k&&!h&&j>=2)
                    update(f[k][h][i-4][j-2],dp[k][h][i][j]);

                 update(f[k][h][i-1][j],f[k][h][i][j]);
                 if(i>=3&&j>=1)update(f[k][h][i-3][j-1],f[k][h][i][j]);
                 if(i>=4&&j>=2)update(f[k][h][i-4][j-2],f[k][h][i][j]);
                }
            }
        }
    }
}
int main() {
    init();
    scanf("%d",&T);
    while(T--) {
        int k,n;
        scanf("%d%d",&n,&k);
        int ans = 0;
        for(int i = 0; i < 2; ++i) {
            for(int j = 0; j < 2; ++j) {
                update(dp[i][j][n][k],ans);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2017-07-30 14:09  meekyan  阅读(199)  评论(0编辑  收藏  举报