您的位置:首页 > 其它

FZU 2200 cleaning dp+预处理

2015-10-06 19:13 309 查看
Problem 2200 cleaning

Accept: 10    Submit: 11

Time Limit: 1000 mSec    Memory Limit : 65536 KB



 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

24 28 3



 Sample Output

416

链接:http://acm.fzu.edu.cn/problem.php?pid=2200

做法:
dp 一维,第几个人,第二维是已经选了几个人,第三维是当前的状态,0 表示当前这位没选,前一位也没选,1表示当前这位没选,前一位选了,2,3类似。

枚举开头两个人的状态,然后预处理dp ,当处理到 i+2 的时候,如果状态和开始枚举的一样,就把值加进real[i]中。预处理出来的real就是最后的答案

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <set>
#include <map>
#define ll long long//试试

ll dp[1010][1010][4];//人数
ll real[1010][1010];
ll mod = 1000000007;
void init()
{
memset(real,0,sizeof real);
for(int i=0;i<2;i++)//1
{
for(int j=0;j<2;j++)//2
{
memset(dp,0,sizeof dp);
dp[2][0][i+j*2]=1;

for(int ii=3;ii<=1002;ii++)//位置
{
for(int jj=0;jj<=ii+2;jj++)//人数
{
for(int a=0;a<4;a++)//前一个
{
if((a&2)==0)
dp[ii][jj][0]=(dp[ii][jj][0]+dp[ii-1][jj][a])%mod;

if((a&2))
dp[ii][jj][1]=(dp[ii][jj][1]+dp[ii-1][jj][a])%mod;

if((a&1)==0&&(a&2)==0&&jj)
dp[ii][jj][2]=(dp[ii][jj][2]+dp[ii-1][jj-1][a])%mod;

if((a&1)==0&&(a&2)&&jj)
dp[ii][jj][3]=(dp[ii][jj][3]+dp[ii-1][jj-1][a])%mod;
}

for(int a=0;a<4;a++)
{
if((a^(i+j*2))==0)//和初始状态没区别
{
real[ii-2][jj]=(real[ii-2][jj]+dp[ii][jj][a])%mod;
//if(dp[ii][jj][a])
//		int kkk=0;
}
}

//if(i==0&&j==0)
//	printf("ii %d   jj %d   dp %d \n",ii,jj,real[ii][jj]);
}
}
}
}

}

int main()
{
init();
int t;
scanf("%d",&t);
while(t--)
{
int n,kk;
scanf("%d%d",&n,&kk);//

int ans=0;
printf("%I64d\n",real
[kk]%mod);

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp