51Nod 1327 棋盘游戏 —— 延迟DP

题目: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=55,xm=205,mod=1e9+7;
int n,m,l[xn],r[xn],f[xm][xm][xm],jc[xm],jcn[xm],sl[xm],sr[xm];
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return f?ret:-ret;
}
ll pw(ll a,int b)
{
  ll ret=1;
  for(;b;b>>=1,a=(a*a)%mod)
    if(b&1)ret=(ret*a)%mod;
  return ret;
}
void init()
{
  jc[0]=1;
  for(int i=1;i<=m;i++)jc[i]=((ll)jc[i-1]*i)%mod;
  jcn[m]=pw(jc[m],mod-2);
  for(int i=m-1;i>=0;i--)jcn[i]=((ll)jcn[i+1]*(i+1))%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<0)x+=mod;}
int main()
{
  n=rd(); m=rd(); init();
  for(int i=1;i<=n;i++)l[i]=rd(),r[i]=rd(),sl[l[i]]++,sr[m-r[i]+1]++;
  for(int i=1;i<=m;i++)sr[i]+=sr[i-1];
  f[0][0][0]=1;
  for(int i=0,num=0;i<m;i++,num=num+sl[i])//
    for(int j=max(0,sl[i+1]-1);j<=i-num;j++)//剩余
      for(int k=0;k<=min(i,n);k++)//填r
    {
      if(!f[i][j][k])continue;
      if(sl[i+1])
        upt(f[i+1][j+1-sl[i+1]][k],(ll)f[i][j][k]*A(j+1,sl[i+1])%mod);
      //,printf("f[%d][%d][%d]=%d A(%d,%d)=%lld f[%d][%d][%d]=%d
",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+1][j+1][k],f[i][j][k]);//0
      if(sr[i+1]>k&&j>=sl[i+1])
        upt(f[i+1][j-sl[i+1]][k+1],(ll)f[i][j][k]*A(j,sl[i+1])%mod*(sr[i+1]-k)%mod);
      //,printf("sr=%d k=%d f[%d][%d][%d]=%d f[%d][%d][%d]=%d
",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+1]&&j>=sl[i+1])
        upt(f[i+1][j-sl[i+1]][k],(ll)f[i][j][k]*A(j,sl[i+1])%mod*(num-sr[i+1])%mod);
      //,printf("!l!r:f[%d][%d][%d]=%d A=%lld k=%d f[%d][%d][%d]=%d
",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
",i,j,k,f[i][j][k]);
    }
  int ans=0;
  for(int j=0;j<=m-2*n;j++)upt(ans,f[m][j][n]);
  //,printf("f[%d][%d][%d]=%d
",m,j,n,f[m][j][n]);
  printf("%d
",ans);
  return 0;
}
原文地址:https://www.cnblogs.com/Zinn/p/9799015.html