棋盘游戏 51Nod - 1327

6 篇文章 0 订阅

题解:在放置棋子时仅仅要求左右满足条件与n的顺序无关,考虑一个二维dp数组,dp[i][j]代表放到了第i列还有j列没有放棋子,但是这个二维dp没有维护右限的信息,所以考虑增加一维代表有多少行到达了右限但没有棋子,将l和r区间的限制统计,可以得到dp转移方程:

 

 

dp[a+1][b+1-l[a+1]][c+r[a+1]]+=dp[a][b][c]*sum[b+1][l[a+1]]%mod;

枚举到当第i列,有l[i]行必须要放左区间了,从空的列中选择放入当前列不放入,同时加上到达右限的区间

dp[a+1][b-l[a+1]][c+r[a+1]]+=dp[a][b][c]*sum[b][l[a+1]]%mod*num[a+1]%mod; 

枚举到当第i列,有l[i]行必须要放左区间了,从空的列中选择放入当前列放作用于不在左右限制的行,同时加上到达右限的区间

dp[a+1][b-l[a+1]][c+r[a+1]-1]+=dp[a][b][c]*sum[b][l[a+1]]%mod*(c+r[a+1])%mod;

枚举到当第i列,有l[i]行必须要放左区间了,从空的列中选择放入但是当前列放入右限区间,同时加上到达右限的区间

比较难!!!!!

ac代码:

#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define ll long long
using namespace std;
int read(){
    char c;int x=0,y=1;while(c=getchar(),(c<'0'||c>'9')&&c!='-');
    if(c=='-') y=-1;else x=c-'0';while(c=getchar(),c>='0'&&c<='9')
        x=x*10+c-'0';return x*y;
}
const int maxn=2e2+10;
const ll mod=1e9+7;
ll dp[maxn][maxn][55];
ll sum[maxn][maxn];
int l[maxn],r[maxn],num[maxn];
int main( ){
    int n=read(),m=read();
    memset(dp,0,sizeof(dp));
    for(int a=0;a<=m;a++){
        sum[a][0]=1;
        for(int b=1;b<=a;b++) sum[a][b]=sum[a][b-1]*(a-b+1)%mod;
    }
    for(int a=1;a<=n;a++){
        int u=read(),v=read();
        l[u]++,r[m-v+1]++;
        num[u+1]++;
        num[m-v+1]--;
    }
    for(int a=2;a<=m;a++) num[a]+=num[a-1];
    dp[0][0][0]=1;
    for(int a=0;a<m;a++){
        for(int b=0;b<=a;b++){
            for(int c=0;c<=n;c++){
                if(!dp[a][b][c]) continue;
                if(b+1>=l[a+1])
                    dp[a+1][b+1-l[a+1]][c+r[a+1]]+=dp[a][b][c]*sum[b+1][l[a+1]]%mod,dp[a+1][b+1-l[a+1]][c+r[a+1]]%=mod;
                if(b>=l[a+1])
                    dp[a+1][b-l[a+1]][c+r[a+1]]+=dp[a][b][c]*sum[b][l[a+1]]%mod*num[a+1]%mod,dp[a+1][b-l[a+1]][c+r[a+1]]%=mod;
                if(b>=l[a+1]&&c+r[a+1]>=1)
                    dp[a+1][b-l[a+1]][c+r[a+1]-1]+=dp[a][b][c]*sum[b][l[a+1]]%mod*(c+r[a+1])%mod,dp[a+1][b-l[a+1]][c+r[a+1]-1]%=mod;
            }
        }
    }
    ll ans=0;
    for(int a=0;a<=m;a++) ans=(ans+dp[m][a][0])%mod;
    printf("%lld\n",ans);
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值