zoukankan      html  css  js  c++  java
  • 题解「AT1983 [AGC001E] BBQ Hard」

    转载注明来源:https://www.cnblogs.com/syc233/p/13627377.html


    这题的模型转化挺巧妙的,不过也都是套路。


    套路:从棋盘的 ((0,0)) 走到 ((n,m)) ,每步只能向上或向右走的方案数为 ({n+m choose n})

    考虑一个DP:令 (f_{i,j}) 表示从 ((0,0)) 走到 ((i,j)) 的方案数,有转移方程:

    [f_{i,j}=f_{i-1,j}+f_{i,j-1} ]

    尝试用组合数替换一下,得:

    [{i+j choose i}={i+j-1 choose i-1}+{i+j+1 choose i} ]

    这恰好是杨辉三角,说明 (f_{i,j}={i+j choose i})


    回到这道题。

    由上面的套路,不难想出一个解法:枚举 (i,j) ,求出 ((0,0)) 走到 ((a_i+a_j,b_i+b_j)) 的方案数。

    然而这和暴力没什么两样,都是 (O(n^2)) 级别的,因为终点与 (i,j) 都有关。

    尝试平移下棋盘,则变成了求 ((-a_i,-b_i)) 走到 ((a_j,b_j)) 的方案数。

    这样就好统计了。将每一个 (f_{-a_i,-b_i}) 赋初值 (1) ,DP统计答案即可。

    因为题目中 (i ot =j) ,还要减去 (i=j) 的情况,即从 ((-a_i,-b_i)) 走到 ((a_i,b_i)) 的方案数,即 ({2a_i+2b_i choose 2a_i})

    因为每一对 ((i,j)) 只算一次,所以最后答案还要除以 (2)

    因为是模意义下除以 (2) ,所以应该乘上 (2)(10^9+7) 意义下的逆元。


    ( ext{Code}:)

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #define maxn 200005
    #define maxm 2001
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    const lxl mod=1e9+7;
    
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    int N,A[maxn],B[maxn];
    lxl f[(maxm<<1)+5][(maxm<<1)+5],ans;
    lxl inv[(maxm<<2)+5],fac[(maxm<<2)+5],inv2[(maxm<<2)+5];
    
    inline void init()
    {
    	inv[0]=inv[1]=fac[0]=fac[1]=inv2[0]=inv2[1]=1;
    	for(int i=2;i<=(maxm<<2);++i)
    	{
    		inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    		fac[i]=fac[i-1]*i%mod;
    		inv2[i]=inv2[i-1]*inv[i]%mod;
    	}
    }
    
    inline lxl C(int n,int m)
    {
    	return fac[n]*inv2[m]%mod*inv2[n-m]%mod;
    }
    
    int main()
    {
    	// freopen("AT1983.in","r",stdin);
    	read(N);
    	init();
    	for(int i=1;i<=N;++i)
    	{
    		read(A[i]),read(B[i]);
    		++f[maxm-A[i]][maxm-B[i]];
    	}
    	for(int i=1;i<=(maxm<<1);++i)
    		for(int j=1;j<=(maxm<<1);++j)
    			(f[i][j]+=(f[i-1][j]+f[i][j-1])%mod)%=mod;
    	for(int i=1;i<=N;++i)
    	{
    		(ans+=f[maxm+A[i]][maxm+B[i]])%=mod;
    		(ans+=mod-C(2*A[i]+2*B[i],2*A[i]))%=mod;
    	}
    	printf("%lld
    ",ans*inv[2]%mod);
    	return 0;
    }
    
    
  • 相关阅读:
    Linux C下的正则表达式
    中英文i18 vue参数传递
    es map的用法
    webpack中publicPath问题
    prop中如何获取vue data中的数据 中英文方案
    利用map reduce方法将对象转成数组
    WPF 踩坑笔记2
    WPF 踩坑笔记1
    RabbitMQ 高阶用法 之 x-expire 过期时间设置
    JANUSEC应用网关1.0发布,提供一站式安全交付能力
  • 原文地址:https://www.cnblogs.com/syc233/p/13627377.html
Copyright © 2011-2022 走看看