zoukankan      html  css  js  c++  java
  • AT1983 [AGC001E] BBQ Hard

    前言

    学到了一个(trick)
    对于一个组合数 (C_{x+y}^x)可以看成是从((0,0))((x,y))的路径条数。

    解法

    对于这题而言,(C_{a_i+b_i+a_j+b_j}^{a_i+a_j})就表示从点((0,0))到点((a_i+a_j,b_i+b_j))的路径条数。
    然后你会发现这并没有什么卵用
    于是又出现了一个(trick)。考虑平移这两个点变成((-a_i,-b_i))((a_j,b_j))。然后把所有的((-a_i,-b_i))(+1)之后就可以进行一个简单的(DP)

    [dp[i][j]=dp[i][j]+dp[i-1][j]+dp[i][j-1] ]

    (dp[i][j])表示从某一个出发点到((i,j))的路径条数。把所有(dp[a[i]][b[i]])的答案加起来就是一个初步的答案。由于题目里边要求(i<j),所以减去重复的答案然后除以(2),就可以了。重复的答案就是(C_{2(a_i+b_i)}^{2a_i})

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define R register
    #define LL long long
    const int inf = 0x3f3f3f3f;
    const int MAXN = 2e5 + 10;
    const int P = 1e9 + 7;
    const int MAXM = 5e3 + 10;
    const int D = 2e3 + 10;
    
    inline int read() {
    	char a = getchar(); int x = 0,f = 1;
    	for(; a > '9' || a < '0'; a = getchar()) if(a == '-') f = -1;
    	for(; a >= '0' && a <= '9' ;a = getchar()) x = x * 10 + a - '0';
    	return x * f;
    }
    
    int n;
    int a[MAXN], b[MAXN]; 
    int f[MAXM][MAXM];
    int fac[MAXM * 2], ifac[MAXM * 2];
    
    inline int qpow(int x,int k) {
    	int res = 1;
    	while(k) {
    		if ( k & 1 ) res = 1LL * res * x % P;
    		x = 1LL * x * x % P;
    		k >>= 1; 
    	}
    	return res;
    }
    
    inline int C(int x, int y) {
    	return 1LL * fac[x] * ifac[y] % P * ifac[x - y] % P;
    }
    
    int main() {
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
    	n = read(); 
    	for(R int i = 1; i <= n ; i++) a[i] = read(), b[i] = read(); 
    	for(R int i = 1; i <= n ; i++) f[D - a[i]][D - b[i]] ++;
    	
    	for(R int i = 1; i <= D * 2; i++) 
    		for(R int j = 1; j <= D * 2; j++)
    			f[i][j] += ( f[i - 1][j] + f[i][j - 1] ) % P, f[i][j] %= P;
    			
    	fac[0] = 1;
    	for(R int i = 1; i <= D * 4; i++) fac[i] = 1LL * fac[i - 1] * i % P;
    	ifac[D * 4] = qpow( fac[D * 4], P - 2 );
    	for(R int i = D * 4 - 1; i >= 0 ; i--) 
    		ifac[i] = 1LL * ifac[i + 1] * (i + 1) % P;
    		
    	int ans = 0;
    	for ( R int i = 1; i <= n; i++) {
    		ans = ( ans + f[D + a[i]][D + b[i]] ) % P;
    		ans = ( ans - C ( a[i] * 2 + b[i] * 2, a[i] * 2 ) ) % P;
    	}
    	
    	ans = ( ( ans % P ) + P ) % P;
    	printf("%lld
    ", 1LL * ans * qpow( 2, P - 2) % P );
    	return 0;	
    }
    

    这题一个更高端的版本是扩展到三维。式子大概这样的。

    [sum_{i=1}^nsum_{j=i+1}^nC^{a_i+a_j}_{a_i+b_i+c_i+a_j+b_j+c_j} imes C^{b_i+b_j}_{b_i+c_i+b_j+c_j} ]

    看成三维的点去做就可以了。实际上这个式子就可以看成是三维的点之间先选一维的路,在选一维的路。做法同上。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define R register
    #define LL long long
    const int inf = 0x3f3f3f3f;
    const int MAXN = 2e5+10;
    const int P = 1e8 + 7;
    const int N = 150 + 5;
    
    inline int read() {
    	char a = getchar(); int x = 0,f = 1;
    	for(; a > '9' || a < '0'; a = getchar()) if(a == '-') f = -1;
    	for(; a >= '0' && a <= '9' ;a = getchar()) x = x * 10 + a - '0';
    	return x * f;
    }
    
    int n;
    int a[MAXN], b[MAXN], c[MAXN];
    int dp[N * 2 + 1][N * 2 + 1][N * 2 + 1];
    int C[N * 6 + 1][N * 6 + 1];
    
    signed main() {
    //	freopen("cyj.in","r",stdin);
    	//freopen("cyj.out","w",stdout);	
    	n = read();
    	for(R int i = 1; i <= n; i++) a[i] = read(), b[i] = read(), c[i] = read();
    	for(R int i = 1; i <= n; i++) dp[N - a[i]][N - b[i]][N - c[i]]++;
    	for(R int i = 1; i <= N * 2; i++)
    		for(R int j = 1; j <= N * 2; j++)
    			for(R int k = 1; k <= N * 2; k++)
    				dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j][k] + dp[i][j - 1][k] + dp[i][j][k - 1]) % P;
    	for(R int i = 0; i <= N * 6; i++) {
    		C[i][0] = 1;
    		for(R int j = 1; j <= i; j++)
    			C[i][j] =( C[i - 1][j] + C[i - 1][j - 1] ) % P;
    	}
    	int ans = 0;
    	for(R int i = 1; i <= n; i++) {
    		ans = ( ans + dp[N + a[i]][N + b[i]][N + c[i]] ) ;
    		ans = ((ans - 1LL * C[(a[i] + b[i] + c[i]) * 2][a[i] * 2] * C[(b[i] + c[i]) * 2][b[i] * 2]) % P + P) % P ;
    	}
    	ans = 1LL * ans * (P + 1) / 2 % P; 
    	printf("%d
    ", ans % P);
    	return 0;	
    }
    
  • 相关阅读:
    Java实现批量下载《神秘的程序员》漫画
    mysql远程连接:ERROR 1130 (HY000): Host '*.*.*.*' is not allowed to connect to this MySQL server解决办法
    opencv学习_15 (利用cmake查看opencv的源码)
    jobs 命令
    中断子系统6_中断嵌套处理
    JPA一对多映射
    JPA Map映射
    JPA集合映射
    JPA删除实体
    JPA查找实体
  • 原文地址:https://www.cnblogs.com/clover4/p/12890252.html
Copyright © 2011-2022 走看看