• AtCoder Grand Contest 018 E


    Description

    给出平面上坐标单调不降的三个矩形 (A,B,C) ,你需要在 (A) 选择一个起点, (B) 选择一个位置休息, (C) 选择一个终点,期间你可以向上和向右走
    求所有选择的方案和
    题面

    Solution

    写起来有点恶心
    先考虑一个简单的问题,求 从 ((0,0)) 出发,走到矩形 ((0,0),(x,y)) 内任意一点的方案数

    [sum_{i=0}^{x}sum_{j=0}^{y}C_{i+j}^{i} ]

    用杨辉三角合并得到:

    [sum_{i=0}^{x}C_{i+y+1}^{i+1} ]

    再用杨辉三角合并成:

    [C_{x+y+2}^{x+1}-1 ]

    这个合并的过程可以抽象的理解为杨辉三角的合并,也可以分析组合意义:
    (sum_{i=0}^{n}C_{i+x}^{x})相当于枚举了一个总数,在这个总数中取 (x)
    我们可以转化为 (C_{n+x+1}^{x+1}), 相当于多取出了一个球,其中第 (x+1) 个球的位置作为这个枚举的总数,也就是上式的 (i+x)

    然后求从 ((0,0)) 走到矩形 ((x1,y1),(x2,y2)) 内的任意一点的方案就可以用二维前缀和求出了

    再回到这题:
    考虑枚举中转点,我们不如枚举进入矩形 (B) 的点和走出的点,那么路上经过的点都可以作为休息点,那么算出每一对进出点的贡献再乘上路径长度就行了
    设这两个点分别为 ((x1,y1),(x2,y2))
    那么分三段算就行了 (F(1)+F(2)+F(3))*(x2-x1+y2-y1+1)
    实际上把 (x2+y2+1) 和 (-x1-y1) 的贡献分开算就可以做到 (O(n)) 的了,至于 (F(2)) 的方案是可以由两条路径拼起来的,不需要多做讨论
    硬是不能感性理解的话,给出式子:
    枚举两个点,要求: (sumsum (x[j]-x[i]+y[j]-y[i]+1)*C_{x[j]-x[i]+y[j]-y[i]}^{x[j]-x[i]}*S_i*T_j)
    其中 (S_i) 表示点 (i) 达到第一个矩形内所有点的方案, (T_i) 表示 点 (i) 到第三个矩形的方案
    然后我们发现 (sum_{j}C_{x[j]-x[i]+y[j]-y[i]}^{x[j]-x[i]}*T_j=T_i)
    那么原式子就跟 (j) 无关了,变为 (sum(x[i]+y[i]+1)*S_i*T_i-sum(-x[j]-y[j])*S_j*T_j)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=2e6+10,mod=1e9+7;
    int x[10],y[10],Fac[N],inv[N];
    inline void priwork(){
    	Fac[0]=inv[0]=inv[1]=1;
    	for(int i=1;i<N;i++)Fac[i]=1ll*Fac[i-1]*i%mod;
    	for(int i=2;i<N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    	for(int i=2;i<N;i++)inv[i]=1ll*inv[i]*inv[i-1]%mod;
    }
    inline void add(int &x,int y){x+=y;if(x<0)x=(x%mod+mod)%mod;if(x>=mod)x-=mod;}
    inline int C(int a,int b){
    	return 1ll*Fac[a]*inv[b]%mod*inv[a-b]%mod;
    }
    inline int G(int x,int y){return C(x+y,x);}
    inline int F(int x1,int y1,int x2,int y2){
    	return (1ll*G(x2+1,y2+1)-G(x1,y2+1)-G(x2+1,y1)+G(x1,y1))%mod;
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      priwork();
      for(int i=1;i<=6;i++)cin>>x[i];
      for(int i=1;i<=6;i++)cin>>y[i];
    
      int ans=0;
      for(int x1=x[3],y1=y[3];x1<=x[4];x1++)
    	  add(ans,1ll*F(x1-x[2],y1-1-y[2],x1-x[1],y1-1-y[1])*F(x[5]-x1,y[5]-y1,x[6]-x1,y[6]-y1)%mod*(mod-x1-y1)%mod);
      for(int x1=x[3],y1=y[3];y1<=y[4];y1++)
    	  add(ans,1ll*F(x1-1-x[2],y1-y[2],x1-1-x[1],y1-y[1])*F(x[5]-x1,y[5]-y1,x[6]-x1,y[6]-y1)%mod*(mod-x1-y1)%mod);
      for(int x2=x[3],y2=y[4];x2<=x[4];x2++)
    	  add(ans,1ll*F(x2-x[2],y2-y[2],x2-x[1],y2-y[1])*F(x[5]-x2,y[5]-y2-1,x[6]-x2,y[6]-y2-1)%mod*(x2+y2+1)%mod);
      for(int x2=x[4],y2=y[3];y2<=y[4];y2++)
    	  add(ans,1ll*F(x2-x[2],y2-y[2],x2-x[1],y2-y[1])*F(x[5]-x2-1,y[5]-y2,x[6]-x2-1,y[6]-y2)%mod*(x2+y2+1)%mod);
    
      cout<<ans<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    Django终端打印SQL语句
    Django之缓存
    Django总结三
    Django之信号
    Django之Form的ModelForm
    git下
    Ajax实现文件的上传
    operator模块
    Django之Form自定义验证规则
    New Concept English Two 32 88
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8717898.html
Copyright © 2020-2023  润新知