zoukankan      html  css  js  c++  java
  • fzyzojP3782 -组合数问题

    这个ai<=2000有点意思

    启发我们用O(W^2)的算法

    FFT不存在,对应关系过紧

    考虑组合意义转化建模,再进行分离

     

    (除以2不需要逆元不懂为啥,但是算个逆元总不费事)

    由于终点可能在起点的右下,所以,从左上到右下要再做一遍

    但是每个终点正上方的起点统计了两次,再减掉即可

    (注意大力卡常:

    1.s2[i][j]没有,就不用算了

    2.f,ans开long long 尽量减少取模

    3.组合数用阶乘计算

    #include<bits/stdc++.h>
    #define il inline
    #define reg register int
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=4000+4;
    const int M=200000+5;
    const int mod=1e9+7;
    ll f[N][N];
    int s1[N][N],s2[N][N];
    int jie[N],inv[N];
    int qm(int x,int y){
        int ret=1;
        while(y){
            if(y&1) ret=(ll)ret*x%mod;
            x=(ll)x*x%mod;
            y>>=1;
        }
        return ret;
    }
    ll mo1(ll x){
        return x>=4e12?x%mod:x;
    }
    ll mo2(ll x){
        return x>=0?x%mod:x;
    }
    int n;
    int C(int n,int m){
        return (ll)jie[n]*inv[m]%mod*inv[n-m]%mod;
    }
    int main(){
        rd(n);
        int a,b;
        jie[0]=1;
        for(reg i=1;i<=4000;++i) jie[i]=(ll)jie[i-1]*i%mod;
        inv[4000]=qm(jie[4000],mod-2);
        for(reg i=3999;i>=0;--i) inv[i]=(ll)inv[i+1]*(i+1)%mod;
        ll ans=0;
        for(reg i=1;i<=n;++i){
            rd(a);rd(b);
            int x=a-b+2000,y=b+2000;
            s1[x][y]++;
            x=-a+b+2000,y=-b+2000;
            s2[x][y]++;
            ans=mo2(ans+mod-C(2*a,2*b));
        }
        ans%=mod;
    ///    cout<<ans<<endl;
        for(reg i=4000;i>=1;--i){
            for(reg j=4000;j>=1;--j){
                f[i][j]=mo1(f[i+1][j]+f[i][j+1]+s1[i][j]);
                if(s2[i][j])ans=mo2(ans+(ll)f[i][j]*s2[i][j]);
            }
        }
        ans%=mod;
    //    cout<<ans<<endl;
        for(reg i=1;i<=4000;++i){
            for(reg j=4000;j>=1;--j){
                f[i][j]=mo1(f[i-1][j]+f[i][j+1]+s1[i][j]);
                ans=s2[i][j]?(ans+(ll)f[i][j]*s2[i][j])%mod:ans;
                s1[i][j]+=s1[i][j+1];
                ans=s2[i][j]?(ans-(ll)s1[i][j]*s2[i][j]+(ll)10*mod)%mod:ans;
            }
        }
        ll inv2=5e8+4;
        ans=ans*inv2%mod;
        printf("%lld",ans);
        return 0;
    }
    
    }
    signed main(){
        freopen("3782.in","r",stdin);
        freopen("3782.out","w",stdout);
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/2/8 18:52:17
    */

    总结:

    核心:转化问题,分离终点和起点

     和这个题的最后差分分离思路有异曲同工之处:AGC 018E.Sightseeing Plan——网格路径问题观止

  • 相关阅读:
    LeetCode【21】 Merge Two Sorted Lists
    LeetCode【2】Add two numbers
    LeetCode【125】Valid Palindrome
    LeetCode【9】Palindrome Number
    LeetCode【20】Valid Parentheses
    LeetCode【1】Two Sum
    LeetCode【8】string to integer(atoi)
    LeetCode【168】Excel Sheet Column Title
    lambda表达式
    UML类图
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10356714.html
Copyright © 2011-2022 走看看