• G


    AGC001E
    AT1983

    首先我是完全不会,所以学习了别人的小想法

    朴素的算法是(O(n^2))的,因此一定会炸,所以我们要将(i)(j)分离,以求得一个(O(n))或与(n)无关的算法

    但是万恶的组合数让我们毫无头绪,这时,你会发现,你迷失在了数字的海洋里

    为了改变现状,你决定,成为偶像 考虑组合数的组合意义

    (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))的走法数量

    把原点平移一下,(C_{a_i+b_i+a_j+b_j}^{a_i+a_j})表示为从点((-a_i,-b_i))((a_j,b_j))的走法数量

    考虑把所有的((-a_i,-b_i))标记(dp)值+1,

    然后(dp[i][j] = dp[i - 1][j] + dp[i][j - 1])递推

    统计所有((a_i,b_i))(dp)值的和

    但是这样会重复,对于原题的式子(sum_{i = 1}^{n} sum_{j = i + 1}^{n} C_{a_i+a_j+b_i+b_j}^{a_i+a_j}),我们算了(i == j) 时的情况,同时每对((i,j))还算了两遍

    减去即可

    
    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 2050;
    const int mod = 1e9 + 7;
    
    int n;
    int a[200050],b[200050];
    int dp[N << 1][N << 1];
    
    long long fac[10050];
    long long inv[10050];
    long long ksm(long long x,int y){
        long long z = 1;
        while(y){
            if(y & 1) z = z * x % mod;
            y >>= 1;
            x = x * x % mod;
        }
        return z;
    }
    long long C(int n,int m){
        if(n < m || m < 0) return 0;
        if(n == m || m == 0) return 1;
        return fac[n] * inv[m] % mod * inv[n - m] % mod;
    }
    
    int main(){
        fac[0] = 1;
        for(int i = 1; i <= 10000; ++ i) fac[i] = fac[i - 1] * i % mod;
        inv[10000] = ksm(fac[10000],mod - 2); 
        for(int i = 9999; i >= 0; -- i) inv[i] = inv[i + 1] * (i + 1) % mod;
    
        scanf("%d",&n);
        for(int i = 1; i <= n; ++ i) 
        scanf("%d%d",&a[i],&b[i]);
        
        for(int i = 1; i <= n; ++ i)
        dp[2001 - a[i]][2001 - b[i]] += 1;
        
        for(int i = 1; i <= 4005; ++ i)
        for(int j = 1; j <= 4005; ++ j){
            dp[i][j] += (dp[i - 1][j] + dp[i][j - 1]) % mod;
            dp[i][j] %= mod;
        }
       
        long long ans = 0;
        
        /*for(int i = 1998; i <= 2003; ++ i) {
        for(int j = 1999; j <= 2002; ++ j)
        printf("%d ",dp[i][j]);
        puts("");
        }*/
        
        for(int i = 1; i <= n; ++ i){
        	//printf("%d
    ",dp[2001 + a[i]][2001 + b[i]]);
        	ans = ans + dp[2001 + a[i]][2001 + b[i]], ans %= mod;
        }
        
        //printf("%lld
    ",ans);
        
        for(int i = 1; i <= n; ++ i){
            ans -= C(a[i] + a[i] + b[i] + b[i], a[i] + a[i]);
            ans = (ans + mod) % mod;
        }
        
        ans = ans * ksm(2, mod - 2) % mod;
        
        printf("%lld
    ",ans);
        
        return 0;
    }
    
    
  • 相关阅读:
    原创 ios绘制 圆形气泡
    ios 线程安全单例写法
    (转)ios中点击地图控件MKMapView的某点获取该点的经纬度
    使用正则提取url(iOS)
    MAC系统崩溃,使用命令行复制硬盘内容
    UISearchBar控件UI操作
    app发布流程详解
    App Store审核指南(中文版)2010版
    GCD详解
    iOS扫描二维码(系统方法)
  • 原文地址:https://www.cnblogs.com/zzhzzh123/p/13345693.html
Copyright © 2020-2023  润新知