• COGS 有标号的二分图计数系列


    其实这三道题都是不错的……(虽然感觉第三题略套路了……)

    分别写一下做法好了……

    COGS2392 有标号的二分图计数 I

    这个就很简单了,Noip难度。

    显然可以直接认为黑点和白点分别位于二分图两侧,枚举二分图左侧的点数,如果左侧的点数为$k$,那么就有$C_n^k$种选择方案,并且有$k(n-k)$条边可选,因为每条边都可以选或不选,因此答案就是

    egin{align}sum_{k=0}^n C_n^k 2^{k(n-k)}end{align}

    由于只需求出一个答案,直接快速幂搞一搞即可,复杂度$O(nlog n)$。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define LL long long
     5 #define fac(x) (((x)<(0))?(0):(f[(x)]))
     6 using namespace std;
     7 const int maxn=100010;
     8 const LL p=998244353ll;
     9 LL inv(LL);
    10 LL qpow(LL,LL);
    11 LL C(int,int);
    12 int n;
    13 LL f[maxn<<1],ans=0;
    14 int main(){
    15 #define MINE
    16 #ifdef MINE
    17     freopen("QAQ_bipartite_one.in","r",stdin);
    18     freopen("QAQ_bipartite_one.out","w",stdout);
    19 #endif
    20     scanf("%d",&n);
    21     f[0]=1ll;
    22     for(int i=1;i<=n;i++)f[i]=f[i-1]*i%p;
    23     for(int i=0;i<=n;i++)(ans+=C(n,i)*qpow(2ll,(LL)(n-i)*i%(p-1ll)))%=p;
    24     printf("%d",(int)ans);
    25     return 0;
    26 }
    27 LL inv(LL x){
    28     return qpow(x,p-2ll);
    29 }
    30 LL qpow(LL a,LL b){
    31     LL ans=1ll;
    32     for(;b;b>>=1,(a*=a)%=p)if(b&1ll)(ans*=a)%=p;
    33     return ans;
    34 }
    35 LL C(int n,int m){
    36     return fac(n)*inv(fac(m)*fac(n-m)%p)%p;
    37 }
    View Code

    (这代码是我很久之前写的了,十分丑陋,不要介意……)

     

    COGS2393 有标号的二分图计数 II

    设上一题的指数生成函数是$F(x)$,这题的指数生成函数为$G(x)$,强制必须连通的指数生成函数是$H(x)$,显然有

    egin{align}G=sum_{i=0}^inftyfrac{H^i}{i!}=e^{H}end{align}

    然后考虑$F$和$H$的关系,如果某个二分图有$k$个连通块,那么它在第一题中就会被计算$2^k$次,所以我们需要把每一项乘上$2^k$,因此就有

    egin{align}F=sum_{i=0}^inftyfrac{2^iH^i}{i!}=e^{2H}end{align}

    然后可以看出来$F=G^2$,也就是$G=sqrt F$,跑一下多项式开根即可求出$G$。

    但是还有一个最重要的问题,这个$F$不好算……

    $F$显然是没法直接算了,但观察到$F$的形式和卷积比较像,因此我们可以尝试把$F$化成卷积形式。显然最碍事的就是$2^{n(n-k)}$了,只要解决掉它,一切就都好说了。

    首先我们有$k(n-k)=k^2-nk$,把$nk$用$frac{n^2+k^2-(n-k)^2}2$替换之后就可以得到$k(n-k)=frac{n^2-k^2-(n-k)^2}2$,因此$2^{k(n-k)}=frac{left(sqrt 2 ight)^{n^2}}{left(sqrt 2 ight)^{k^2}left(sqrt 2 ight)^{(n-k)^2}}$,然后就是卷积形式了,一遍NTT即可求出$F$。

    ps:我没有想出来,这是看了ad学长的题解才明白的,感觉还是比较妙啊……

    在$mod 998244353$意义下是存在$sqrt 2$的,暴力一下并把暴力出的答案直接写到代码里即可。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=262200,p=998244353,g=3,sqrt_2=116195171,inv_2=499122177;
     6 void NTT(int*,int,int);
     7 void getsqrt(int*,int*,int);
     8 void getinv(int*,int*,int);
     9 int qpow(int,int,int);
    10 int n,N=1,A[maxn],B[maxn],fac[maxn],pw[maxn];
    11 int main(){
    12     freopen("QAQ_bipartite_two.in","r",stdin);
    13     freopen("QAQ_bipartite_two.out","w",stdout);
    14     scanf("%d",&n);
    15     while(N<=n)N<<=1;
    16     A[0]=fac[0]=pw[0]=1;
    17     for(int i=1;i<=n;i++){
    18         fac[i]=(long long)fac[i-1]*i%p;
    19         pw[i]=qpow(sqrt_2,(long long)i*i%(p-1),p);
    20         A[i]=qpow((long long)fac[i]*pw[i]%p,p-2,p);
    21     }
    22     NTT(A,N<<1,1);
    23     for(int i=0;i<(N<<1);i++)A[i]=(long long)A[i]*A[i]%p;
    24     NTT(A,N<<1,-1);
    25     for(int i=0;i<=n;i++)A[i]=(long long)A[i]*pw[i]%p;
    26     fill(A+n+1,A+(N<<1),0);
    27     getsqrt(A,B,N);
    28     printf("%d",(int)((long long)B[n]*fac[n]%p));
    29     return 0;
    30 }
    31 void NTT(int *A,int n,int tp){
    32     for(int i=1,j=0,k;i<n-1;i++){
    33         k=n;
    34         do j^=(k>>=1);while(j<k);
    35         if(i<j)swap(A[i],A[j]);
    36     }
    37     for(int k=2;k<=n;k<<=1){
    38         int wn=qpow(g,(tp>0?(p-1)/k:(p-1)/k*(long long)(p-2)%(p-1)),p);
    39         for(int i=0;i<n;i+=k){
    40             int w=1;
    41             for(int j=0;j<(k>>1);j++,w=(long long)w*wn%p){
    42                 int a=A[i+j],b=(long long)w*A[i+j+(k>>1)]%p;
    43                 A[i+j]=(a+b)%p;
    44                 A[i+j+(k>>1)]=(a-b+p)%p;
    45             }
    46         }
    47     }
    48     if(tp<0){
    49         int inv=qpow(n,p-2,p);
    50         for(int i=0;i<n;i++)A[i]=(long long)A[i]*inv%p;
    51     }
    52 }
    53 void getsqrt(int *A,int *C,int n){
    54     static int B[maxn],D[maxn];
    55     fill(C,C+(n<<1),0);
    56     C[0]=1;
    57     for(int k=2;k<=n;k<<=1){
    58         copy(A,A+k,B);
    59         fill(B+k,B+(k<<1),0);
    60         getinv(C,D,k);
    61         NTT(B,k<<1,1);
    62         NTT(D,k<<1,1);
    63         for(int i=0;i<(k<<1);i++)B[i]=(long long)B[i]*D[i]%p;
    64         NTT(B,k<<1,-1);
    65         for(int i=0;i<k;i++)C[i]=(long long)(C[i]+B[i])*inv_2%p;
    66     }
    67 }
    68 void getinv(int *A,int *C,int n){
    69     static int B[maxn];
    70     fill(C,C+(n<<1),0);
    71     C[0]=qpow(A[0],p-2,p);
    72     for(int k=2;k<=n;k<<=1){
    73         copy(A,A+k,B);
    74         fill(B+k,B+(k<<1),0);
    75         NTT(B,k<<1,1);
    76         NTT(C,k<<1,1);
    77         for(int i=0;i<(k<<1);i++)C[i]=C[i]*((2-(long long)B[i]*C[i]%p+p)%p)%p;
    78         NTT(C,k<<1,-1);
    79         fill(C+k,C+(k<<1),0);
    80     }
    81 }
    82 int qpow(int a,int b,int p){
    83     int ans=1;
    84     for(;b;b>>=1,a=(long long)a*a%p)if(b&1)ans=(long long)ans*a%p;
    85     return ans;
    86 }
    View Code

     

    COGS2395 有标号的二分图计数 III

    你还记得$F=e^{2H}$不……

    然后就很好说了,多项式$ln$之后答案就是对应项系数$/2$……

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=262200,p=998244353,g=3,sqrt_2=116195171,inv_2=499122177;
     6 void NTT(int*,int,int);
     7 void getln(int*,int*,int);
     8 void getinv(int*,int*,int);
     9 void getderivative(int*,int*,int);
    10 void getintegrate(int*,int*,int);
    11 int qpow(int,int,int);
    12 int n,N=1,A[maxn],B[maxn],fac[maxn],pw[maxn];
    13 int main(){
    14     freopen("QAQ_bipartite_thr.in","r",stdin);
    15     freopen("QAQ_bipartite_thr.out","w",stdout);
    16     scanf("%d",&n);
    17     while(N<=n)N<<=1;
    18     A[0]=fac[0]=pw[0]=1;
    19     for(int i=1;i<=n;i++){
    20         fac[i]=(long long)fac[i-1]*i%p;
    21         pw[i]=qpow(sqrt_2,(long long)i*i%(p-1),p);
    22         A[i]=qpow((long long)fac[i]*pw[i]%p,p-2,p);
    23     }
    24     NTT(A,N<<1,1);
    25     for(int i=0;i<(N<<1);i++)A[i]=(long long)A[i]*A[i]%p;
    26     NTT(A,N<<1,-1);
    27     for(int i=0;i<=n;i++)A[i]=(long long)A[i]*pw[i]%p;
    28     fill(A+n+1,A+(N<<1),0);
    29     getln(A,B,N);
    30     printf("%d",(int)((long long)B[n]*fac[n]%p*inv_2%p));
    31     return 0;
    32 }
    33 void NTT(int *A,int n,int tp){
    34     for(int i=1,j=0,k;i<n-1;i++){
    35         k=n;
    36         do j^=(k>>=1);while(j<k);
    37         if(i<j)swap(A[i],A[j]);
    38     }
    39     for(int k=2;k<=n;k<<=1){
    40         int wn=qpow(g,(tp>0?(p-1)/k:(p-1)/k*(long long)(p-2)%(p-1)),p);
    41         for(int i=0;i<n;i+=k){
    42             int w=1;
    43             for(int j=0;j<(k>>1);j++,w=(long long)w*wn%p){
    44                 int a=A[i+j],b=(long long)w*A[i+j+(k>>1)]%p;
    45                 A[i+j]=(a+b)%p;
    46                 A[i+j+(k>>1)]=(a-b+p)%p;
    47             }
    48         }
    49     }
    50     if(tp<0){
    51         int inv=qpow(n,p-2,p);
    52         for(int i=0;i<n;i++)A[i]=(long long)A[i]*inv%p;
    53     }
    54 }
    55 void getln(int *A,int *C,int n){
    56     static int B[maxn];
    57     getderivative(A,B,n);
    58     getinv(A,C,n);
    59     NTT(B,n<<1,1);
    60     NTT(C,n<<1,1);
    61     for(int i=0;i<(n<<1);i++)B[i]=(long long)B[i]*C[i]%p;
    62     NTT(B,n<<1,-1);
    63     getintegrate(B,C,n);
    64     fill(C+n,C+(n<<1),0);
    65 }
    66 void getinv(int *A,int *C,int n){
    67     static int B[maxn];
    68     fill(C,C+(n<<1),0);
    69     C[0]=qpow(A[0],p-2,p);
    70     for(int k=2;k<=n;k<<=1){
    71         copy(A,A+k,B);
    72         fill(B+k,B+(k<<1),0);
    73         NTT(B,k<<1,1);
    74         NTT(C,k<<1,1);
    75         for(int i=0;i<(k<<1);i++)C[i]=C[i]*((2-(long long)B[i]*C[i]%p+p)%p)%p;
    76         NTT(C,k<<1,-1);
    77         fill(C+k,C+(k<<1),0);
    78     }
    79 }
    80 void getderivative(int *A,int *C,int n){
    81     for(int i=1;i<n;i++)C[i-1]=(long long)A[i]*i%p;
    82     C[n-1]=0;
    83 }
    84 void getintegrate(int *A,int *C,int n){
    85     for(int i=1;i<n;i++)C[i]=(long long)A[i-1]*qpow(i,p-2,p)%p;
    86     C[0]=0;
    87 }
    88 int qpow(int a,int b,int p){
    89     int ans=1;
    90     for(;b;b>>=1,a=(long long)a*a%p)if(b&1)ans=(long long)ans*a%p;
    91     return ans;
    92 }
    View Code
  • 相关阅读:
    对协程的一些理解
    JUC中Lock和ReentrantLock介绍及源码解析
    JUC中AQS简介
    Executor框架简介
    CyclicBarrier简介
    CountDownLatch简介
    Semaphore简介
    ThreadPoolExecutor简介
    AtomicInteger简介
    synchronized和volatile简介
  • 原文地址:https://www.cnblogs.com/hzoier/p/6597833.html
Copyright © 2020-2023  润新知