标签:攻击 type std namespace out typedef amp 棋盘 pid
https://www.luogu.org/problem/show?pid=2051
题意:n*m棋盘,n,m<=100 问在棋盘上放炮 使得任意两个炮都互补攻击(即同行或者同列最多放两个)的方法数?
定义状态,dp[i][j][k] 已经放了i行 有j列放一个炮,有k列放2个炮 (并不需要准确知道当前棋盘的状态)
状态转移时,按照第i行如何放炮即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=9999973;
const int N=1e2+20;
int n,m;
ll dp[N][N][N];//dp[i][j][k] 已经放了i行 有j列放一个炮,有k列放2个炮
ll C(ll x)
{
return x*(x-1)/2;
}
int main()
{
while(cin>>n>>m)
{
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<=m;j++)
{
for(int k=0;k<=m-j;k++)
{
dp[i+1][j][k]=(dp[i+1][j][k]+dp[i][j][k])%mod;//第i+1行不放
//第i+1行 放一个
if(m-j-k>=1)
dp[i+1][j+1][k]=(dp[i+1][j+1][k]+dp[i][j][k]*(m-j-k))%mod;//放在空列上
if(j-1>=0)
dp[i+1][j-1][k+1]=(dp[i+1][j-1][k+1]+dp[i][j][k]*j)%mod;//放在有一个棋子的列上
//第i+1行 放两个
if(m-j-k>=2)
dp[i+1][j+2][k]=(dp[i+1][j+2][k]+dp[i][j][k]*C(m-j-k))%mod;//空列
if(m-j-k>=1&&j>=1)
dp[i+1][j][k+1]=(dp[i+1][j][k+1]+dp[i][j][k]*(m-j-k)*j)%mod;//一个在空列,一个在有一个棋子的列上
if(j-2>=0)
dp[i+1][j-2][k+2]=(dp[i+1][j-2][k+2]+dp[i][j][k]*C(j))%mod;//两个都在有一个棋子的列上
}
}
}
ll ans=0;
for(int j=0;j<=m;j++)
for(int k=0;k<=m-j;k++)
ans=(ans+dp[n][j][k])%mod;
cout<<ans<<endl;
}
return 0;
}
标签:攻击 type std namespace out typedef amp 棋盘 pid
原文地址:http://www.cnblogs.com/HIKARI1149/p/6857566.html