zoukankan      html  css  js  c++  java
  • CCPC 2016 G Marriage(HDU6270) 组合数学:容斥原理+NTT+启发式合并

    CCPC 2016 G Marriage(HDU6270) 组合数学:容斥原理+NTT+启发式合并

    呜呜呜,为什么我长春CCPC,知乎上出题人的题解都咕着,我写了I的题解,结果没人看呢,PTA只有4A,不会是都不补题吧T_T(其实是百度不到我)。本来想蹭一波阅读量,大失败。

    咳咳,回到正题。
    题目意思是,一个城市里总共有N个家庭,第i个家庭有ai个男孩和bi个女孩,已知城市里男女比例1:1,在不近亲结婚且异性恋情况下,共有多少种不同的婚配方法(有一个人配偶不同即不同)
    对于每个家庭,我们可以得到至少有i对近亲配对的方法。从而得到一个生成函数。对于这n个多项式,我们乘起来就得到了,城市里至少有i对近亲结婚的方法。我们可以用容斥原理计算,这里需要注意的是,不要忘记了给剩下的人配对,即总共有N对。对至少有i对近亲结婚的方法,要乘上(N-i)!

    一开始WA了好多发,后来发现。。。我优先队列没pop干净,不过我塞了n个,每次取两个再塞一个进行n-1次,为什么我只pop一个没pop干净呢?疑惑。。。
    代码如下:

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 const long long MOD=998244353;
      4 const long long g=3;
      5 vector <long long> c[300010];
      6 long long x1[300010],x2[300010],p[300010],inv[300010],invp[300010],rev[200010],t,sum,a[100010],b[100010];
      7 long long ksm(long long x,long long y)
      8 {
      9     long long res=x;
     10     long long ans=1;
     11     while (y)
     12     {
     13         if (y&1) ans=ans*res%MOD;
     14         res=res*res%MOD;
     15         y=y>>1;
     16     }
     17     return ans;
     18 }
     19 struct cmp
     20 {
     21     bool operator()(int x, int y) 
     22     {
     23         return c[x].size()>c[y].size();
     24     }
     25 };priority_queue <long long,vector<long long>,cmp> q;
     26 void init()
     27 {
     28     p[0]=1;
     29     for (int i=1;i<=300000;i++)
     30     {
     31         p[i]=p[i-1]*i%MOD;
     32     }
     33     inv[1]=1;
     34     for(int i=2;i<=300000;i++)
     35     {
     36         inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
     37     }
     38     invp[0]=1;
     39     invp[1]=1;
     40     for (int i=2;i<=300000;i++)
     41     {
     42         invp[i]=invp[i-1]*inv[i]%MOD;
     43     }
     44 }
     45 long long C(long long x,long long y)
     46 {
     47     return (p[x]*invp[y]%MOD)*invp[x-y]%MOD;
     48 }
     49 inline void NTT(long long *z,long long len,long long invv) 
     50 { 
     51     long long bit=0; 
     52     while ((1<<bit)<len) 
     53     { 
     54         ++bit; 
     55     } 
     56     for(int i=0;i<=len-1;i++) 
     57     { 
     58         rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1)); 
     59         if (i<rev[i])swap(z[i],z[rev[i]]); 
     60     } 
     61     for (int mid=1;mid<len;mid*=2) 
     62     { 
     63         long long tmp=ksm(g,(MOD-1)/(mid*2)); 
     64         if (invv==-1) tmp=ksm(tmp,MOD-2); 
     65         for (int i=0;i<len;i+=mid*2) 
     66         {     
     67             long long omega=1; 
     68             for (long long j=0;j<mid;++j,omega=omega*tmp%MOD) 
     69             { 
     70                 long long x=z[i+j],y=omega*z[i+j+mid]%MOD;         
     71                 z[i+j]=(x+y)%MOD;
     72                 z[i+j+mid]=(x-y+MOD)%MOD; 
     73             } 
     74         } 
     75     } 
     76     if (invv==-1) 
     77     for (int i=0;i<len;i++)
     78     {
     79         z[i]=z[i]*inv[len]%MOD;
     80     }
     81 }
     82 void mul(vector<long long> &x,vector<long long> &y,vector<long long> &z)
     83 {
     84     long long len=1; 
     85     while (len<x.size()+y.size()) 
     86     { 
     87         len=len<<1;
     88     } 
     89     for (int i=0;i<x.size();i++)
     90     {
     91         x1[i]=x[i];
     92     }
     93     for (int i=x.size();i<len;i++)
     94     {
     95         x1[i]=0;    
     96     }
     97     for (int i=0;i<y.size();i++)
     98     {
     99         x2[i]=y[i];
    100     }
    101     for (int i=y.size();i<len;i++)
    102     {
    103         x2[i]=0;    
    104     }
    105     NTT(x1,len,1);
    106     NTT(x2,len,1);
    107     for (int i=0;i<len;i++)
    108     {
    109         x1[i]=x1[i]*x2[i]%MOD;
    110     }
    111     NTT(x1,len,-1);
    112     for (int i=0;i<x.size()+y.size()-1;i++)
    113     {
    114         z.push_back(x1[i]);
    115     }
    116 }
    117 int main()
    118 {
    119     long long t,n,i,j,flag,ans;
    120     init();
    121     scanf("%lld",&t);
    122     while (t--)
    123     {
    124         scanf("%lld",&n);
    125         for (i=0;i<=n*2;i++)
    126         {
    127             c[i].clear();
    128         }
    129         sum=0;
    130         for (i=1;i<=n;i++)
    131         {
    132             scanf("%lld%lld",&a[i],&b[i]);
    133             sum=sum+a[i];
    134             for (j=0;j<=b[i]&&j<=a[i];j++)
    135             {
    136                 c[i].push_back((C(a[i],j)*C(b[i],j)%MOD)*p[j]%MOD);
    137             }
    138             q.push(i);
    139         }
    140         for (i=n+1;i<n*2;i++)
    141         { 
    142             int x=q.top();q.pop();
    143             int y=q.top();q.pop();
    144             mul(c[x],c[y],c[i]);
    145             q.push(i);
    146         }
    147         while (!q.empty()) q.pop();
    148         flag=1;
    149         ans=0;
    150         for (i=0;i<c[n*2-1].size();i++)
    151         {
    152             ans=ans+flag*p[sum-i]*c[n*2-1][i]%MOD;
    153             ans=(ans+MOD)%MOD;
    154             flag=0-flag;
    155         }
    156         ans=(ans+MOD)%MOD;
    157         printf("%lld
    ",ans);
    158     }
    159     return 0;
    160 }
    View Code of G

    后记:明天JSCPC啦,早睡早睡。疫情之下,第一场线下赛。

  • 相关阅读:
    【幻化万千戏红尘】qianfengDay03-java基础学习:for循环,switch,if
    Hexo | 博客文章链接优化之abbrlink
    Hexo 集成 Gitalk 评论系统
    Linux对一个目录及其子目录所有文件添加权限
    PhpStorm配置使用phpunit单元测试
    php根据当前定位经纬度排序
    mysql根据当前定位经纬度排序
    linux压缩和解压缩命令
    PHP常见数学函数及BC高精度数学函数用法示例
    vagrant package 打包自己的box镜像
  • 原文地址:https://www.cnblogs.com/idyllic/p/14019505.html
Copyright © 2011-2022 走看看