• 【题解/总结】两双手(格路问题)/格路问题的某一本质


    【题解】两双手(格路问题)

    题目大意:求从((0,0))((Ex,Ey))不经过给定障碍点的方案数。你每次移动只能是加上向量(e_1)或者向量(e_2)(e_1,e_2)中的基底都是整数。

    考虑转化一下这个问题,从某个点走到在他右上角的某点需要加上(ae_1+be_2),这样我们就可以解出(a,b)。我们把((a,b))拿出来建立新的坐标系,就变成了简单的格路问题了。结合【题解】CF559C C. Gerald and Giant Chess(容斥+格路问题)就可以直接做了。当不存在((a,b))是非负整数解时,可以把这个点删掉。

    考虑为什么可以这样解出两个值((a,b))转化,只能在这道题里用吗?实际上,格路问题可以抽象成这样一种问题:

    你有两种元素,每种元素每次可以增加一一次只能加一种元素,元素之间互相独立。现在要你从((0,0))加到((n,m)),问你多少组方案。方案的本质是对于加元素的操作构成的合法序列的总数。

    用序列的角度看问题,​有(a_i)(i)元素,你要好好排列出(sum a_i)长度的序列,问这些序列不同的分布。这就可以拓展为多维的问题。

    这应该是此类格路问题的本质。

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(c<48||c>57)f|=c==45,c=getchar();
          while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    int n,A1,A2,B1,B2;
    const int maxn=5e2+5;
    const int mod=1e9+7;
    typedef pair<int,int> P;
    P data[maxn];
    int jc[1000001],inv[1000001],cnt,dp[maxn];
    
    
    inline int ksm(const int&ba,const int&p){
          int ret=1;
          for(int t=p,b=ba%mod;t;t>>=1,b=1ll*b*b%mod)
    	    if(t&1) ret=1ll*ret*b%mod;
          return ret;
    }
    
    inline void pre(const int&n){
          *jc=*inv=1;
          for(int t=1;t<=n;++t) jc[t]=1ll*jc[t-1]*t%mod;
          inv[n]=ksm(jc[n],mod-2);
          for(int t=n-1;t;--t)  inv[t]=1ll*inv[t+1]*(t+1)%mod;
    }
    
    inline bool get(P&s){
          int x=s.first,y=s.second;
          int a=(B2*x-B1*y)/(A1*B2-A2*B1);
          int b=(A2*x-A1*y)/(A2*B1-A1*B2);
          s=(pair<int,int>){a,b};
          return a*A1+b*B1==x&&a*A2+b*B2==y&&a>=0&&b>=0;
    }
    
    inline int c(const int&n,const int&m){return n<m?0:1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;}
    inline int grid(const int&x,const int&y){return c(x+y,x);}
    int main(){
          int f=qr(),g=qr();
          data[++cnt]=(pair<int,int>){f,g}; n=qr();
          A1=qr(); A2=qr();
          B1=qr(); B2=qr();
          if(!get(data[1])) return !puts("0");
          pre(1e6);
          for(int t=1,t1,t2;t<=n;++t){
    	    t1=qr(); t2=qr();
    	    data[++cnt]=(pair<int,int>){t1,t2};
    	    if(!(get(data[cnt])&&data[cnt]<=data[1])) --cnt;
          }
          sort(data+1,data+cnt+1);
          for(int t=1;t<=cnt;++t){
    	    dp[t]=grid(data[t].first,data[t].second);
    	    for(int i=1;i<t;++i)
    		  dp[t]=(dp[t]-1ll*dp[i]*grid(data[t].first-data[i].first,data[t].second-data[i].second)%mod+mod)%mod;
          }
          printf("%d
    ",dp[cnt]);
          return 0;
    }
    
    
    
  • 相关阅读:
    Out of hay
    P3028 [USACO10OCT]汽水机Soda Machine
    P3619 魔法
    P2847 [USACO16DEC]Moocast(gold)奶牛广播-金
    P2830 写程序
    c#DateTime与unix时间戳互相转换
    C# UdpClient使用
    udp单播,广播,多播实现(ReceiveFromAsync,SendToAsync)
    udp广播,单播,多播
    C#实现异步阻塞TCP(Send,Receive,Accept,Connect)
  • 原文地址:https://www.cnblogs.com/winlere/p/11566828.html
Copyright © 2020-2023  润新知