• [ACG001E] BBQ hard [dp]


    题面:

    传送门

    思路:

    首先,一个暴力的想法

    对于每一对pack,求出f(ai+aj,bi+bj),其中f(x,y)=(x+y)!/(x!y!),也就是x个a,y个b的排列方式个数

    然后转化模型,将f数组变化成这样的形式:f(x,y)表示一个x行y列的方格图,左下走到右上的方法数

    然后将所有的f放到一个图中,就变成了:左下的n个点(-ai,-bi)到右上的n个点(ai,bi)的总方法数(任意一个出发任意一个到达)

    用DAGdp把这个方法数求出来,就是sigma(f(ai+aj,bi+bj))(i=1...n,j=1...n),减去所有的f(ai+ai,bi+bi)再除以二即可

    注意:MOD1e9+7意义下,要使用乘法逆元

    Code:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define ll long long
     6 #define MOD 1000000007
     7 using namespace std;
     8 inline int read(){
     9     int re=0,flag=1;char ch=getchar();
    10     while(ch>'9'||ch<'0'){
    11         if(ch=='-') flag=-1;
    12         ch=getchar();
    13     }
    14     while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    15     return re*flag;
    16 }
    17 const int dx[3]={0,0,1},dy[3]={0,1,0};
    18 ll dp[4020][4020];int N=2005;bool vis[4020][4020];
    19 int n,xx[200010],yy[200010],qx[200010],qy[200010],head=0,tail=1,maxq=200000;
    20 ll inv[8010],finv[8010],f[8010];
    21 void init(){
    22     int i;inv[1]=finv[1]=1;
    23     for(i=2;i<=8000;i++){
    24         inv[i]=((MOD-MOD/i)*inv[MOD%i])%MOD;
    25     }
    26     f[1]=1;
    27     for(i=2;i<=8000;i++){
    28         f[i]=(f[i-1]*i)%MOD;
    29         finv[i]=(finv[i-1]*inv[i])%MOD;
    30     }
    31 }
    32 int main(){
    33     init();
    34     int i,maxx=0,maxy=0,x,y,tx,ty;ll X=0;
    35     n=read();
    36     for(i=1;i<=n;i++){
    37         xx[i]=read();yy[i]=read();
    38         dp[N-xx[i]][N-yy[i]]+=1;
    39         maxx=max(maxx,xx[i]);maxy=max(maxy,yy[i]);
    40     }
    41     qx[0]=N-maxx,qy[0]=N-maxy;vis[N-maxx][N-maxy]=1;
    42     while(head!=tail){
    43         x=qx[head];y=qy[head];head=(head+1)%maxq;
    44 //        cout<<"dp "<<x<<ends<<y<<ends<<dp[x][y]<<endl;;
    45         for(i=1;i<=2;i++){
    46             tx=x+dx[i];ty=y+dy[i];
    47             if(tx>N+maxx||ty>N+maxy) continue;
    48             dp[tx][ty]=(dp[tx][ty]+dp[x][y])%MOD;
    49 //            cout<<"    to "<<tx<<ends<<ty<<ends<<dp[tx][ty]<<endl;
    50             if(!vis[tx][ty]){
    51                 vis[tx][ty]=1;
    52                 qx[tail]=tx;qy[tail]=ty;tail=(tail+1)%maxq;
    53             }
    54         }
    55     }
    56     for(i=1;i<=n;i++){
    57         X=X+dp[N+xx[i]][N+yy[i]];X%=MOD;
    58         X=X-((f[xx[i]*2+yy[i]*2]*finv[xx[i]*2])%MOD*finv[yy[i]*2])%MOD+MOD;
    59         X%=MOD;
    60     }
    61     printf("%lld
    ",(X*inv[2])%MOD);
    62 }
  • 相关阅读:
    带下拉子菜单的导航菜单
    如何使用myFocus插件制作焦点图效果
    将博客搬至CSDN
    《转》二进制与三进制的那些趣题
    二叉树遍历 (前序 层次 == 深度 广度) 层次遍历
    数组全排列 knuth 分解质因数
    堆排序
    双向快速排序
    二路归并排序
    字符串的排列
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8459140.html
Copyright © 2020-2023  润新知