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 ",ans); } return 0; }