51nod 1327 棋盘游戏
2017-06-18 16:40
127 查看
有一个N行M列的棋盘,即该棋盘被分为N*M格。现在向棋盘中放棋子,每个格子中最多放一个棋子,也可以一个不放。放完棋子后需要满足如下要求:
1)对于第i行来说,其从左往右的前left[i] 个格子(即最左侧的left[i] 个连续的格子)中恰好一共有1个棋子;
2)对于第i行来说,其从右往左的前right[i]个格子(即最右侧的right[i]个连续的格子)中恰好一共有1个棋子;
3)对于每一列来说,这一列上的所有格子内含有的棋子数不得超过1个。
其中,1)与2)条件中,对所有 i 满足 left[i]+right[i] <= M,即两个区间不会相交。
问,符合上述条件情况下棋子的不同放法一共有多少种?输出放法的个数 mod 1,000,000,007后的结果。
例如样例中,只有如下图一种方法。
Input
Output
Input示例
Output示例
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
神奇DP+思路~
用f[i][j][k]表示当前i列,一共放了j枚棋子,有k行的右区间不满足。
不需要把a数组排序,排了也没有用的哼。
我们显然不能同时DP左右区间,所以我们只能在更新的时候强制满足左区间,DP右区间。
因为每一列最多只能填1个,所以我们可以枚举我们把这个棋子填在什么位置。
对于每一列i,我们预处理出l为左区间的右边界==i的行数,r为右区间的左边界==i的行数,block为i既不在左区间也不在右区间的行数。
那么就有四种放置情况:满足一个左区间,满足一个右区间,放在一个中间区域(即一个block),以及不放。
满足左区间时,我们从已有左区间中选择一个,然后强制假设之前的j枚棋子中有左区间-1个刚好满足了左区间,其余同理。
我枚举区间的时候i是从0开始的导致代码很难看,i+1表示的都是真正的i的位置!
1)对于第i行来说,其从左往右的前left[i] 个格子(即最左侧的left[i] 个连续的格子)中恰好一共有1个棋子;
2)对于第i行来说,其从右往左的前right[i]个格子(即最右侧的right[i]个连续的格子)中恰好一共有1个棋子;
3)对于每一列来说,这一列上的所有格子内含有的棋子数不得超过1个。
其中,1)与2)条件中,对所有 i 满足 left[i]+right[i] <= M,即两个区间不会相交。
问,符合上述条件情况下棋子的不同放法一共有多少种?输出放法的个数 mod 1,000,000,007后的结果。
例如样例中,只有如下图一种方法。
Input
第一行包含两个整数,N,M,其中1<=N<=50,2<=M<=200. 之后有N行,每行两个数left[i],right[i],其中,1<=left[i],right[i]<=M,且 left[i]+right[i] <= M。
Output
一个整数,即符合条件的方案数mod 1,000,000,007后的结果。
Input示例
2 4 1 2 2 1
Output示例
1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
神奇DP+思路~
用f[i][j][k]表示当前i列,一共放了j枚棋子,有k行的右区间不满足。
不需要把a数组排序,排了也没有用的哼。
我们显然不能同时DP左右区间,所以我们只能在更新的时候强制满足左区间,DP右区间。
因为每一列最多只能填1个,所以我们可以枚举我们把这个棋子填在什么位置。
对于每一列i,我们预处理出l为左区间的右边界==i的行数,r为右区间的左边界==i的行数,block为i既不在左区间也不在右区间的行数。
那么就有四种放置情况:满足一个左区间,满足一个右区间,放在一个中间区域(即一个block),以及不放。
满足左区间时,我们从已有左区间中选择一个,然后强制假设之前的j枚棋子中有左区间-1个刚好满足了左区间,其余同理。
我枚举区间的时候i是从0开始的导致代码很难看,i+1表示的都是真正的i的位置!
#include<cstdio> #include<cstring> #include<iostream> using namespace std; #define mod 1000000007 #define ll long long int n,m,f[202][202][52],c[202][202],mi[202],ans,l,r,block; struct node{ int l,r; }a[51]; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();} while(ch>='0' && ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return x*f; } void add(int &a,int b) { a+=b; if(a>=mod) a-=mod; } int main() { n=read();m=read(); for(int i=1;i<=n;i++) a[i].l=read(),a[i].r=m-read()+1; for(int i=0;i<=201;i++) c[i][0]=1; for(int i=1;i<=201;i++) for(int j=1;j<=i;j++) add(c[i][j],c[i-1][j]+c[i-1][j-1]); mi[0]=1; for(int i=1;i<=201;i++) mi[i]=(ll)mi[i-1]*i%mod; for(int i=1;i<=201;i++) for(int j=1;j<=i;j++) c[i][j]=(ll)c[i][j]*mi[j]%mod; f[0][0][0]=1; for(int i=0;i<m;i++) { l=r=block=0; for(int j=1;j<=n;j++) l+=(a[j].l==i+1),r+=(a[j].r==i+1),block+=(a[j].l<i+1 && a[j].r>i+1); for(int j=l-1;j<=i+1;j++) for(int k=0;k<=n-r;k++) { if(j+1>=l && l>=1) add(f[i+1][j+1-l][k+r],(ll)c[l][1]*c[j][l-1]%mod*f[i][j][k]%mod); if(j>=l) { add(f[i+1][j+1-l][k+r],(ll)c[j][l]*f[i][j][k]%mod); if(k+r>=1) add(f[i+1][j-l][k+r-1],(ll)c[j][l]*f[i][j][k]%mod*c[k+r][1]%mod); if(block) add(f[i+1][j-l][k+r],(ll)c[j][l]*f[i][j][k]%mod*c[block][1]%mod); } } } for(int i=0;i<=m;i++) add(ans,f[m][i][0]); printf("%d\n",ans); return 0; }
相关文章推荐
- 51nod 1327 棋盘游戏
- 51nod 1605-棋盘游戏(博弈)
- HDU 1281 棋盘游戏 (二分图+枚举每点是否为匹配关键)
- 棋盘游戏
- 51nod 1070 Bash游戏 V4(博弈——找规律)
- hdu 1281 棋盘游戏 二分图匹配
- 九度OJ 1091:棋盘游戏 (DP、BFS、DFS、剪枝)
- hdu 1281 棋盘游戏 (二分图最大匹配)
- 51nod 1381 硬币游戏
- bzoj4705: 棋盘游戏
- 第十四周项目5-体会棋盘游戏中的数据存储
- 第十四周项目五:棋盘游戏中的数据存储
- 第14周项目5 体会棋盘游戏中的数据存储
- 第十四周项目 5 体会棋盘游戏中的数据存储
- 第14周 项目5 棋盘游戏
- C语言二分图匹配(4)___棋盘游戏(Hdu 1281)
- 51nod 1418 放球游戏
- 51nod-1534 棋子游戏
- 51Nod - 1069 Nim游戏
- HDU 1281 棋盘游戏(二分匹配)