zoukankan      html  css  js  c++  java
  • 组合数学+ntt+启发式合并+容斥原理

    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<queue>
    
    using namespace std;
    typedef long long ll;
    const int maxn=3e5+10, mod = 998244353, G = 3, Gi = 332748118;
    typedef pair<int, int> P;
    ll quick(ll a,ll b,ll m)
    {
        ll ans=1;
        while(b>0)
        {
            if(b&1)
                ans=ans*a%m;
            a=a*a%m;
            b>>=1;
        }
        return ans;
    }
    
    ll jiecheng[maxn];
    void ini_zuhelogn()
    {
        jiecheng[0]=1;
        for(int i=1;i<maxn;i++)
        {
            jiecheng[i]=jiecheng[i-1]*i%mod;
        }
    }
    ll zuhe_logn(int m,int n)
    {
        if(jiecheng[0]!=1)
            ini_zuhelogn();
        ll ans=((jiecheng[m]*quick(jiecheng[n], mod-2, mod))%mod)*quick(jiecheng[m-n], mod-2, mod)%mod;
        return ans;
    }
    
    ll result_len,result[maxn],level=0,trans[maxn];
    
    inline void NTT(ll *A, int type) {
        for(int i = 0; i < result_len; i++)
            if(i < trans[i]) swap(A[i], A[trans[i]]);
        for(int mid = 1; mid < result_len; mid <<= 1) {
            ll Wn = quick( type == 1 ? G : Gi , (mod - 1) / (mid << 1),mod);
            for(int j = 0; j < result_len; j += (mid << 1)) {
                ll w = 1;
                for(int k = 0; k < mid; k++, w = (w * Wn) % mod) {
                     int x = A[j + k], y = w * A[j + k + mid] % mod;
                     A[j + k] = (x + y) % mod,
                     A[j + k + mid] = (x - y + mod) % mod;
                }
            }
        }
    }
    void ntt(ll *a,int a_len,ll *b,int b_len)
    {
        result_len=1;level=0;
        while(result_len<=a_len+b_len)
        {
            result_len<<=1;
            level++;
        }
        for(int i=a_len;i<result_len;i++)
            a[i]=0;
        for(int i=b_len;i<result_len;i++)
            b[i]=0;
        for(int i=0;i<result_len;i++)
            trans[i]=(trans[i>>1]>>1)|((i&1)<<(level-1));
        NTT(a, 1);
        NTT(b, 1);
        for(int i=0;i<result_len;i++)
            result[i]=(a[i]*b[i])%mod;
        NTT(result,-1);
        ll inv=quick(result_len, mod-2, mod);
        for(int i=0;i<result_len;i++)
            result[i]=(result[i]*inv)%mod;
      
    }
    P a[maxn];
    vector<ll> D[maxn];
    priority_queue<P> q;
    ll d1[maxn],d2[maxn];
    int main() {
        ini_zuhelogn();
        int T;
        cin>>T;
        while (T--) {
            int n,m=0;
            cin>>n;
            for(int i=0;i<n;i++)
            {
                
    //            cout<<i<<":"<<endl;
                cin>>a[i].first>>a[i].second;
                m+=a[i].first;
                int t=min(a[i].first,a[i].second);
                D[i].clear();
                D[i].push_back(1);
                for(int j=1;j<=t;j++){
                    D[i].push_back((zuhe_logn(a[i].first, j)*zuhe_logn(a[i].second, j))%mod*jiecheng[j]%mod);
    //                cout<<D[i][j]<<" ";
                }
    //            cout<<endl;
                q.push(make_pair(-t-1, i));
            }
            
            while(q.size()>1)
            {
                int t1=q.top().second,len1=-q.top().first;
                q.pop();
                int t2=q.top().second,len2=-q.top().first;
                q.pop();
    //            cout<<t1<<" "<<len1<<": ";
                for(int i=0;i<len1;i++){
                    d1[i]=D[t1][i];
    //                cout<<d1[i]<<" ";
                }
    //            cout<<endl<<t2<<" "<<len2<<": ";
                for(int i=0;i<len2;i++){
                    d2[i]=D[t2][i];
    //                cout<<d2[i]<<" ";
                }
    //            cout<<endl;
                ntt(d1, len1, d2, len2);
                D[t2].clear();
                for(int i=0;i<len1-1+len2;i++){
    //                cout<<result[i]<<" ";
                    D[t2].push_back(result[i]);
                }
    //            cout<<endl;
                q.push(make_pair(-len1+1-len2, t2));
                
            }
            int t=q.top().second,len=-q.top().first;
            q.pop();
            int flag=1;
            ll ans=0;
            for(int i=0;i<len;i++)
            {
                ans=(ans+flag*jiecheng[m-i]*D[t][i])%mod;
                flag*=-1;
            }
            cout<<(ans+mod)%mod<<endl;
        }
        return 0;
    }
    //1
    //6
    //0 2
    //1 0
    //1 2
    //0 0
    //2 2
    //2 0
  • 相关阅读:
    架构设计的方法学 【转】
    异常处理
    Java中---HashSet中的Set()方法不能加重复值的原因,唯一性
    java中Set集合
    java中foreach语法和总结
    泛型的处理
    迭代器错误处理
    防重复提交
    mqtt安装和使用
    字符串正则替换
  • 原文地址:https://www.cnblogs.com/King-of-Dark/p/13025341.html
Copyright © 2011-2022 走看看