51Nod 1327 棋盘游戏 —— 延迟DP
2024-09-08 15:36:36
题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1327
看博客:https://www.cnblogs.com/Narh/p/9791875.html
思路就是按列DP,如果不是必须填就先空下这一列,记录一下目前有多少可用的空列,遇到一个 l 的结束时就从中选一些列放上棋子,并乘个排列;
对于 r,方案数在当前列体现,所以要记录当前列可填的位置;
注意别漏了状态,当前可转移的状态是填 l,填 r,不填,填在不是 l 也不是 r 的地方四种转移;
还有各种细节...全仰仗 Narh 提点;
呆滞了半小时...一对拍就发现...在算 A 的地方别忘了写 (ll) !!!
好题啊!
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=,xm=,mod=1e9+;
int n,m,l[xn],r[xn],f[xm][xm][xm],jc[xm],jcn[xm],sl[xm],sr[xm];
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return f?ret:-ret;
}
ll pw(ll a,int b)
{
ll ret=;
for(;b;b>>=,a=(a*a)%mod)
if(b&)ret=(ret*a)%mod;
return ret;
}
void init()
{
jc[]=;
for(int i=;i<=m;i++)jc[i]=((ll)jc[i-]*i)%mod;
jcn[m]=pw(jc[m],mod-);
for(int i=m-;i>=;i--)jcn[i]=((ll)jcn[i+]*(i+))%mod;
}
int A(int n,int m){return (ll)jc[n]*jcn[n-m]%mod;}//(ll)!!!
void upt(int &x,int y){x+=y; while(x>=mod)x-=mod; while(x<)x+=mod;}
int main()
{
n=rd(); m=rd(); init();
for(int i=;i<=n;i++)l[i]=rd(),r[i]=rd(),sl[l[i]]++,sr[m-r[i]+]++;
for(int i=;i<=m;i++)sr[i]+=sr[i-];
f[][][]=;
for(int i=,num=;i<m;i++,num=num+sl[i])//列
for(int j=max(,sl[i+]-);j<=i-num;j++)//剩余
for(int k=;k<=min(i,n);k++)//填r
{
if(!f[i][j][k])continue;
if(sl[i+])
upt(f[i+][j+-sl[i+]][k],(ll)f[i][j][k]*A(j+,sl[i+])%mod);
//,printf("f[%d][%d][%d]=%d A(%d,%d)=%lld f[%d][%d][%d]=%d\n",i,j,k,f[i][j][k],j+1,sl[i+1],A(j+1,sl[i+1]),i+1,j+1-sl[i+1],k,f[i+1][j+1-sl[i+1]][k]);//l
else upt(f[i+][j+][k],f[i][j][k]);//
if(sr[i+]>k&&j>=sl[i+])
upt(f[i+][j-sl[i+]][k+],(ll)f[i][j][k]*A(j,sl[i+])%mod*(sr[i+]-k)%mod);
//,printf("sr=%d k=%d f[%d][%d][%d]=%d f[%d][%d][%d]=%d\n",sr[i+1],k,i,j,k,f[i][j][k],i+1,j-sl[i+1],k+1,f[i+1][j-sl[i+1]][k+1]);//r(+l)
if(num-sr[i+]&&j>=sl[i+])
upt(f[i+][j-sl[i+]][k],(ll)f[i][j][k]*A(j,sl[i+])%mod*(num-sr[i+])%mod);
//,printf("!l!r:f[%d][%d][%d]=%d A=%lld k=%d f[%d][%d][%d]=%d\n",i,j,k,f[i][j][k],A(j,sl[i+1]),num-sr[i+1],i+1,j-sl[i+1],k,f[i+1][j-sl[i+1]][k]);//!l,!r (+l)
// printf("f[%d][%d][%d]=%d\n",i,j,k,f[i][j][k]);
}
int ans=;
for(int j=;j<=m-*n;j++)upt(ans,f[m][j][n]);
//,printf("f[%d][%d][%d]=%d\n",m,j,n,f[m][j][n]);
printf("%d\n",ans);
return ;
}
最新文章
- 禁用SQL Server Management Studio的IntelliSense
- Nginx中防盗链(下载防盗链和图片防盗链)操作记录
- shell应用——主控脚本实现(1)
- 在XML序列化时去除默认命名空间xmlns:xsd和xmlns:xsi
- Evaluation of Expression Tree
- python的浅拷贝和深拷贝
- NGUI如何创建自己的精灵图集
- 微软职位内部推荐-ATG Engineer II
- node.js动态调试
- 《Programming WPF》翻译 第6章 5.我们进行到哪里了?
- MySQL查看索引、表信息、触发器
- SQL基本用法-行转列
- 初学Python之 布尔类型
- 济南清北学堂游记 Day 1.
- Echarts官网展示
- java HMAC_SHA1加密算法
- eclipse中的XML文件无法快捷键注释问题
- SpringMVC入门(基于注解方式实现)
- Python访问MySQL(1):初步使用PyMySQL包
- BLDC无刷直流电机的原理及驱动基础