题目大意:
给你一个N?N和M?M的棋盘,他们如图摆放:
左下角是N?N,然后要你求出在这样一个棋盘上放置K个车的方案数。
PS:车是可以隔空攻击的,比如两个3?3的棋盘,他们平行放置,然后中间没有相连,但是左边的棋盘中的车是可以攻击到右边棋盘的!!!
解题思路:
首先根据对称性,我们可以有:if(W<H) swap(W,H);
然后由于隔空也可以攻击,我们可以有:
if(W>N) W=N;
if(H>N) H=N;
这样我们就可以做到少一点情况了。
然后我们会发现只有这么几种情况:
1.M?M的被N?N包含,这很好做吧,就是在N?N的棋盘中放K个车,直接排列组合一下就行了。
2.(图片来自这里)
这种情况下我们就可以先确定右边突出来的部分怎么放,然后在确定左边的N?N的怎么放
3.
重点是这种情况,我们可以将其分成7块,就根据这两个棋盘的边界可以把其分成7个块,然后我们dp就行了。但是由于本人水平底下,然后又要写高精度,然后我的程序就光荣的MLE了。。。。。。。。。然后经过我的观察发现,极端情况下每个块的放置的车的个数不能超过20个,然后所放置的总和不能超过40个,然后我就果断枚举每一个块应该放置多少个车,最后排列组合计算一下就行了。
具体如何排列组合请看代码。
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#define C(a,b) (fac[(a)]/fac[(b)]/fac[(a)-(b)])
#define P(a,b) (fac[(a)]/fac[(a)-(b)])
const int Mod=10;
using namespace std;
int N,M,W,H,K;
struct gjd_
{
long long cnmbdctr[600];
};
long long fac[30];
struct gjd_ ans={0};
int G[10]={0};
struct gjd_ operator * (struct gjd_ a1,long long a2)
{
if(a2%10==0 && a2!=10)
return a1*(a2/10)*10;
struct gjd_ bb=a1;
for(int i=1;i<=bb.cnmbdctr[0];i++)
{
bb.cnmbdctr[i]*=a2;
if(bb.cnmbdctr[i-1]>=Mod && i!=1)
{
bb.cnmbdctr[i]+=bb.cnmbdctr[i-1]/Mod;
bb.cnmbdctr[i-1]%=Mod;
}
}
for(int i=bb.cnmbdctr[0];bb.cnmbdctr[i]>=Mod;bb.cnmbdctr[0]++,i++)
bb.cnmbdctr[i+1]+=bb.cnmbdctr[i]/Mod,bb.cnmbdctr[i]%=Mod;
return bb;
}
struct gjd_ operator + (struct gjd_ a1,struct gjd_ a2)
{
struct gjd_ bb={0};
bb.cnmbdctr[0]=max(a1.cnmbdctr[0],a2.cnmbdctr[0]);
for(int i=1;i<=bb.cnmbdctr[0];i++)
{
bb.cnmbdctr[i]+=a1.cnmbdctr[i]+a2.cnmbdctr[i];
if(bb.cnmbdctr[i]>=Mod)
{
bb.cnmbdctr[i+1]+=bb.cnmbdctr[i]/Mod;
bb.cnmbdctr[i]%=Mod;
if(i==bb.cnmbdctr[0])
bb.cnmbdctr[0]++;
}
}
return bb;
}
void prt(struct gjd_ a1)
{
printf("%d",(int)a1.cnmbdctr[a1.cnmbdctr[0]]);
for(int i=a1.cnmbdctr[0]-1;i>=1;i--)
printf("%d",(int)a1.cnmbdctr[i]);
return;
}
void counts()
{
struct gjd_ add={1,1};
add=add*C(W,G[1]);
add=add*P(H,G[1])*C(W-G[1],G[2])*P(N-H,G[2]);
add=add*C(H-G[1],G[3])*P(N-W,G[3])*C(N-W-G[3],G[4])*P(N-H-G[2],G[4]);
add=add*C(N-W-G[3]-G[4],G[5])*P(M-(N-H),G[5])*C(N-H-G[2]-G[4],G[6])*P(M-(N-W),G[6]);
add=add*C(M-(N-H)-G[5],G[7])*P(M-(N-W)-G[6],G[7]);
ans=ans+add;
return;
}
void dfs(int cnt,int re)
{
int Max;
if(cnt==7)
{
Max=min(M-(N-H)-G[5],M-(N-W)-G[6]);
if(re<=Max)
{
G[7]=re;
counts();
}
return;
}
else if(cnt==1)
Max=min(min(W,H),re);
else if(cnt==2)
Max=min(min(W-G[1],N-H),re);
else if(cnt==3)
Max=min(min(H-G[1],N-W),re);
else if(cnt==4)
Max=min(min(N-W-G[3],N-H-G[2]),re);
else if(cnt==5)
Max=min(min(N-W-G[3]-G[4],M-(N-H)),re);
else if(cnt==6)
Max=min(min(N-H-G[2]-G[4],M-(N-W)),re);
for(int i=0;i<=Max;i++)
{
G[cnt]=i;
dfs(cnt+1,re-i);
}
return;
}
int main()
{
scanf("%d%d%d%d%d",&N,&M,&W,&H,&K);
fac[0]=1;
for(int i=1;i<=20;i++) fac[i]=fac[i-1]*i;
if(W<H) swap(W,H);
if(W>N) W=N;
if(H>N) H=N;
if(N>=M+W)
{
if(K<=N)
{
ans.cnmbdctr[0]=ans.cnmbdctr[1]=1;
ans=ans*C(N,K);
ans=ans*P(N,K);
}
prt(ans);
}
else if(N>=M+H)
{
if(K>N) cout<<0<<endl;
else
{
int MM=M+W-N;
for(int i=0;i<=min(MM,K);i++)
{
struct gjd_ gg={1,1};
gg=gg*C(M,i);gg=gg*P(MM,i);gg=gg*C(N-i,K-i);gg=gg*P(N,K-i);
ans=ans+gg;
}
prt(ans);
}
}
else
{
dfs(1,K);
prt(ans);
}
return 0;
}
时间: 2024-10-24 03:42:44