sgu-241 The United Fields of Chessboardia

来源:互联网 发布:网络电视直播软件排行 编辑:程序博客网 时间:2024/05/17 18:03

题目大意:

给你一个NNMM的棋盘,他们如图摆放:
这里写图片描述
左下角是NN,然后要你求出在这样一个棋盘上放置K个车的方案数。
PS车是可以隔空攻击的,比如两个33的棋盘,他们平行放置,然后中间没有相连,但是左边的棋盘中的车是可以攻击到右边棋盘的!!!

解题思路:

首先根据对称性,我们可以有:if(W<H) swap(W,H);
然后由于隔空也可以攻击,我们可以有:

if(W>N) W=N;if(H>N) H=N;

这样我们就可以做到少一点情况了。
然后我们会发现只有这么几种情况:
1.MM的被NN包含,这很好做吧,就是在NN的棋盘中放K个车,直接排列组合一下就行了。
2.这里写图片描述(图片来自这里)
这种情况下我们就可以先确定右边突出来的部分怎么放,然后在确定左边的NN的怎么放
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;}
0 0
原创粉丝点击