P2051-线性dp

P2051

题目描述

题目描述

题解

1.第 i i i行什么都不放。
f [ i ] [ j ] [ k ] = f [ i ] [ j ] [ k ] + f [ i − 1 ] [ j ] [ k ] f[i][j][k]=f[i][j][k]+f[i-1][j][k] f[i][j][k]=f[i][j][k]+f[i1][j][k]

2.放1个在空的列。空的列是 m − j − k m-j-k mjk
f [ i ] [ j ] [ k ] = f [ i ] [ j ] [ k ] + f [ i − 1 ] [ j − 1 ] [ k ] × ( m − ( j − 1 ) − k ) f[i][j][k]=f[i][j][k]+f[i−1][j−1][k]×(m−(j−1)−k) f[i][j][k]=f[i][j][k]+f[i1][j1][k]×(m(j1)k)

3.放1个在有1个的列。
f [ i ] [ j ] [ k ] = f [ i ] [ j ] [ k ] + f [ i − 1 ] [ j + 1 ] [ k − 1 ] × ( j + 1 ) f[i][j][k]=f[i][j][k]+f[i−1][j+1][k−1]×(j+1) f[i][j][k]=f[i][j][k]+f[i1][j+1][k1]×(j+1)

4.放2个都在空的列。之前状态乘以C(之前空的列,2)。
f [ i ] [ j ] [ k ] = f [ i ] [ j ] [ k ] + f [ i − 1 ] [ j − 2 ] [ k ] × C ( m − ( j − 2 ) − k ) f[i][j][k]=f[i][j][k]+f[i−1][j−2][k]×C(m−(j−2)−k) f[i][j][k]=f[i][j][k]+f[i1][j2][k]×C(m(j2)k)

5.放1个在空的列,1个在有1个的列:
f [ i ] [ j ] [ k ] = f [ i ] [ j ] [ k ] + f [ i − 1 ] [ j ] [ k − 1 ] × j × ( m − j − ( k − 1 ) ) f[i][j][k]=f[i][j][k]+f[i−1][j][k−1]×j×(m−j−(k−1)) f[i][j][k]=f[i][j][k]+f[i1][j][k1]×j×(mj(k1))

6.放2个在有1个的列。
f [ i ] [ j ] [ k ] = f [ i ] [ j ] [ k ] + f [ i − 1 ] [ j + 2 ] [ k − 2 ] × C ( j + 2 ) f[i][j][k]=f[i][j][k]+f[i−1][j+2][k−2]×C(j+2) f[i][j][k]=f[i][j][k]+f[i1][j+2][k2]×C(j+2)

初始化: f [ 0 ] [ 0 ] [ 0 ] = 1 f[0][0][0]=1 f[0][0][0]=1

代码

#include<bits/stdc++.h>
#define int long long
#define M 100009
using namespace std;
int read(){
	int f=1,re=0;char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f;
}
const int mod=9999973;
int C(int x){return (x*(x-1)/2)%mod;}//实际上是C(x,2);
int n,f[109][109][109],ans,m;//f[i][j][k]表示枚举到第i行,前i行中有j行放了一个炮,有k行放了两个炮 
signed main(){
	n=read(),m=read();
	f[0][0][0]=1;
	for(int i=1;i<=n;i++)
        for(int j=0;j<=m;j++)
            for(int k=0;j+k<=m&&j+k<=2*i;k++){
                f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod;//什么都不放 
                if(j>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k]*(m-(j-1)-k)%mod)%mod;//放1个在空的列 
                if(k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j+1][k-1]*(j+1)%mod)%mod;//放1个在有1个的列 
                if(j>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j-2][k]*C(m-(j-2)-k)%mod)%mod;//放2个都在空的列 
                if(k>=1) f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1]*j%mod*(m-j-(k-1))%mod)%mod;//放1个在空的列,1个在有1个的列 
                if(k>=2) f[i][j][k]=(f[i][j][k]+f[i-1][j+2][k-2]*C(j+2)%mod)%mod;//放2个在有1个的列 
            }
    for(int i=0;i<=m;i++)
        for(int j=0;i+j<=m&&(i+j)<=2*n;j++)
            ans=(ans+f[n][i][j])%mod;
    printf("%lld",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值