首页 > 其他分享 >HDU多校补题

HDU多校补题

时间:2022-08-22 16:25:10浏览次数:100  
标签:HDU a% int dft 多校 len 1ll 补题 EGF

数论

5-02 PN筛

题目链接

7-09 min-25 插值

多项式

7-10 EGF

题目链接
对于有标号的计数问题,考虑EGF,且有已知结论:设无向图的EGF为G,无向连通图的EGF为F,有G=exp(F)。

考虑边出现的概率如何处理:即要满足两个无向连通图在合并的时候,它们之间的边都不存在。那么参照EGF处理组合数的思路,先把每项除掉\((1-p)^{C(n,2)}\),最后乘回去即可。

然后考虑计算答案:\(ans=\sum{[x^n]F^i\times \frac{i}{i!}}\),注意这里除以\(i!\)的意义是:对于每种本质不同的方案,\(i\)个连通块在原来逐渐合并,标号的过程中,有\(i!\)种分配点的方式。

那么容易根据结论化为\(ans=\sum{[x^n]GLn(G)}\)

#include<bits/stdc++.h>
using namespace std;
const int N=(1<<20)+5,P=998244353,G[2]={3,(P+1)/3};
int rv[N],gp[2][N],iv[N];
void print(char name[],int n,int* a){
	printf("%s n=%d\n",name,n);
	for(int i=0;i<n;i++) cout<<a[i]<<" "; puts(""); 
}
inline int fpw(int a,int x){
    int s=1;
    for(;x;x>>=1,a=1ll*a*a%P) if(x&1) s=1ll*s*a%P;
    return s;
}
inline void dft(int* a,int n,int p){
    for(int i=0;i<n;i++) if(i<rv[i]) swap(a[i],a[rv[i]]);
    for(int i=1;i<n;i<<=1){
        for(int j=0;j<n;j+=(i<<1)){
            for(int k=0;k<i;k++){
                int &A=a[i+j+k],&B=a[j+k],t=1ll*gp[p][i+k]*A%P;
                A=B-t; if(A<0) A+=P;
                B=B+t; if(B>=P) B-=P;
            }
        }
    }
    if(p) for(int i=0;i<n;i++) a[i]=1ll*a[i]*iv[n]%P;
}
inline int Rev(int m){
    int p=0,n=1;
    while(n<m) n<<=1,p++;
    for(int i=0;i<n;i++) rv[i]=(rv[i>>1]>>1)|((i&1)<<(p-1));
    return n;
}
inline void poly_mul(int m,int* A,int* B,int* C){
    int n=Rev(m);
    dft(A,n,0); dft(B,n,0);
    for(int i=0;i<n;i++) C[i]=1ll*A[i]*B[i]%P;
    dft(C,n,1);
    fill(C+m,C+n,0);
}
//C=A*B m:需要C的0~(m-1)项,m~(n-1)为空 
int C[N];
inline void poly_inv(int n,int *a, int *b) {
    if (n == 1) {
        b[0] = fpw(a[0],P-2);
        return;
    }
    poly_inv((n + 1) >> 1, a, b);
    int len=Rev(n << 1);
    copy(a, a + n, C);
    fill(C + n, C + len, 0);
    dft(b,len,0); dft(C,len,0);
    for (int i = 0; i < len; ++i) {
        b[i]=1ll*b[i]*(P+2-1ll*b[i]*C[i]%P)%P;
    }
    dft(b,len,1);
    fill(b + n, b + len, 0);
}
//a*b=1,给定a的0~(n-1)项,返回b的0~(n-1)项
//需要保证初始b为空!
inline void poly_Ln(int m,int* a,int* b){
	poly_inv(m,a,b);
	for(int i=0;i<m-1;i++) C[i]=1ll*a[i+1]*(i+1)%P; C[m-1]=0;
    int n=Rev(m<<1);
    fill(C+m,C+n,0);
    dft(C,n,0); dft(b,n,0);
    for(int i=0;i<n;i++) b[i]=1ll*C[i]*b[i]%P;
    dft(b,n,1);
	for(int i=m-1;i;i--) b[i]=1ll*b[i-1]*iv[i]%P; b[0]=0;
	fill(b+m,b+n,0);
}
int fc[N],fv[N];
void init(){
	int n=(1<<20);
	fc[0]=1;
    for(int i=1;i<n;i++) iv[i]=fpw(i,P-2),fc[i]=1ll*fc[i-1]*i%P;
    fv[n-1]=fpw(fc[n-1],P-2);
    for(int i=n-2;~i;i--) fv[i]=1ll*fv[i+1]*(i+1)%P;
    for(int p=0;p<2;p++){
        for(int i=1;i<n;i<<=1){
            gp[p][i]=1;
            int t=fpw(G[p],(P-1)/(i<<1));
            for(int j=i+1;j<(i<<1);j++) gp[p][j]=1ll*gp[p][j-1]*t%P;
        }
    }
}
int A[N],B[N],qy[N];
int main()
{
    init();
    int T; cin>>T;
    while(T--){
    	int q,a,b,p,ip,n=0;
        cin>>q>>a>>b;
        p=(P+1-1ll*a*fpw(b,P-2)%P)%P;
        ip=fpw(p,P-2);
        for(int i=1;i<=q;i++) scanf("%d",&qy[i]),n=max(n,qy[i]);
        A[0]=1;
        for(int i=1;i<=n;i++) A[i]=1ll*fv[i]*fpw(ip,1ll*i*(i-1)/2%(P-1))%P;
		poly_Ln(n+1,A,B);
        int m=Rev((n+1)<<1);
        dft(A,m,0); dft(B,m,0);
        for(int i=0;i<m;i++) A[i]=1ll*A[i]*B[i]%P;
        dft(A,m,1);
        for(int i=1;i<=q;i++){
	        int n=qy[i],s=1ll*fc[n]*fpw(p,1ll*n*(n-1)/2%(P-1))%P*A[n]%P;
	        if(i>1) printf(" ");
	        printf("%d",s);
	    }
	    puts("");
	    for(int i=0;i<m;i++) A[i]=B[i]=0;
    }
    return 0;
}

8-13 求逆

其实是很大力的容斥,直接DP计算每个位置第一次出现排列的方案数,化成多项式形式之后可以求逆计算。

#include<bits/stdc++.h>
using namespace std;
const int N=(1<<20),P=998244353,G[2]={3,(P+1)/3};
int rv[N],gp[2][N],iv[N];
inline int fpw(int a,int x){
    int s=1;
    for(;x;x>>=1,a=1ll*a*a%P) if(x&1) s=1ll*s*a%P;
    return s;
}
inline void dft(int* a,int n,int p){
    //cout<<n<<endl;
    for(int i=0;i<n;i++) if(i<rv[i]) swap(a[i],a[rv[i]]);
    for(int i=1;i<n;i<<=1){
        //int wn=gp[p][i];
        for(int j=0;j<n;j+=(i<<1)){
            //int w=1;
            for(int k=0;k<i;k++){
                int &A=a[i+j+k],&B=a[j+k],t=1ll*gp[p][i+k]*A%P;
                A=B-t; if(A<0) A+=P;
                B=B+t; if(B>=P) B-=P;
            }
        }
    }
    if(p) for(int i=0;i<n;i++) a[i]=1ll*a[i]*iv[n]%P;
}
int Rev(int m){
    int p=0,n=1;
    while(n<=m) n<<=1,p++;
    for(int i=0;i<n;i++) rv[i]=(rv[i>>1]>>1)|((i&1)<<(p-1));
    return n;
}
inline int poly_mul(int m,int* A,int* B,int* C){
    int n=Rev(m);
    dft(A,n,0); dft(B,n,0);
    for(int i=0;i<n;i++) C[i]=1ll*A[i]*B[i]%P;
    dft(C,n,1);
    return n;
}
//C=A*B m:需要C的0-(m-1)项  n:返回C的项数 
int C[N];
inline void poly_inv(int n,int *a, int *b) {
    if (n == 1) {
        b[0] = fpw(a[0],P-2);
        return;
    }
    poly_inv((n + 1) >> 1, a, b);
    int len=Rev(n << 1);
    copy(a, a + n, C);
    fill(C + n, C + len, 0);
    //fill(b + ((n + 1)>>1), b + len, 0);
    dft(b,len,0); dft(C,len,0);
    for (int i = 0; i < len; ++i) {
        //b[i] = Mul(Sub(2, Mul(b[i], C[i])), b[i]);
        b[i]=1ll*b[i]*(P+2-1ll*b[i]*C[i]%P)%P;
    }
    dft(b,len,1);
    fill(b + n, b + len, 0);
}
void init(){
    for(int i=1;i<N;i++) iv[i]=fpw(i,P-2);
    for(int p=0;p<2;p++){
        for(int i=1;i<N;i<<=1){
            gp[p][i]=1;
            int t=fpw(G[p],(P-1)/(i<<1));
            for(int j=i+1;j<(i<<1);j++) gp[p][j]=1ll*gp[p][j-1]*t%P;
        }
    }
}
int n,m,pn[N],fc[N],A[N],B[N],iB[N],f[N];
int main()
{
    init();
    int T; cin>>T;
    while(T--){
        cin>>n>>m;
        memset(A,0,sizeof(A));
        memset(B,0,sizeof(B));
        memset(iB,0,sizeof(iB));
        pn[0]=fc[0]=1;
        for(int i=1;i<=m;i++) pn[i]=1ll*pn[i-1]*n%P,fc[i]=1ll*fc[i-1]*i%P;
        int k=m-n+1;
        for(int i=0;i<=k;i++){
            if(!i) A[i]=0;
            else A[i]=1ll*pn[i-1]*fc[n]%P;
            if(!i) B[i]=1;
            if(i>=n) (B[i]+=1ll*pn[i-n]*fc[n]%P)%=P;
            if(i && i<n) (B[i]+=fc[i])%=P;
        }
        poly_inv(k+1,B,iB);
        poly_mul(k+1+k+1,A,iB,f);
        int s=0;
        for(int i=1;i<=k;i++) (s+=1ll*f[i]*pn[m-i-n+1]%P)%=P;
        //cout<<pn[m]<<" "<<s<<endl;
        cout<<(pn[m]+P-s)%P<<endl;
    }
    return 0;
}

数据结构

8-02 线段树

其它

6-07 暴力

6-11 计数

8-05 均摊复杂度分析

题目链接

标签:HDU,a%,int,dft,多校,len,1ll,补题,EGF
From: https://www.cnblogs.com/szsz/p/16582745.html

相关文章

  • 蔚来杯2022牛客暑期多校训练营加赛 题解
    E.Everyoneisbot对于后\(p\)个人,这\(p\)个人相互制约,一旦有一个人进行复读,剩下的\(p-1\)个人一定会进行复读,那么这个人就会被禁言,对于他来说不是最优策略。此时......
  • HDU2022 第一场
    Backpack我不打但我能补题。明显设\(f_j\)表示容量为j的背包的异或的最大值。但是这样的状态难以进行转移。考虑设\(f_{j,k}\)表示容量为j异或为k是否可行。这样状态......
  • 2022.8.21 多校周报
    总结牛客第九场A一眼看出是尺取法,就A了。B一道很简单的概率dp,状态和转移方程都写出来了,但想着搞前缀和优化,没想到差分,就卡死了,有点可惜。G马拉车加哈希,但卡了除了双......
  • 2022牛客多校 补赛 C Cmostp(区间结尾本质不同子串)
    多次询问求一个串的结尾在\([l,r]\)之间的本质不同子串个数。此题是求一个区间的不同元素的问题,使用扫描线的方法解决,即每次加入一个元素就将这个位置\(+1\),这个元素上一......
  • 2022杭电多校 第9场 1005 Leapfrogger (期望)
    可以说官方题解除了恶心其他人和告诉你这题不难之外没有任何作用。考虑期望的线性性,可以将每一个跳蛙的每一个亡语单独考虑。令\(f_n\)代表剩余\(n\)个随从,其中有一个是......
  • 2022杭电多校第十场1008 Minimum Diameter(树的直径的一些性质)
    解决本题分为两个部分:维护树的直径,合并多个树的直径树的直径有如下性质:1,从任一点出发,到达最远的点是直径的其中一端,从这一点出发可以到达最远的点是直径的另一端。或者说......
  • STL中map容器的应用(HDU1263水果题解)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1263题目描述:TimeLimit:2000MS;MemoryLimit:65536K;夏天来了~Joe经营着一个不大的水果店.他认为生存之道就......
  • 2022杭电多校第2~10场集(赛后补题)
    打完十场回顾一下之前一些的题都是简单题难的我不会继续努力  Luxurycruiseship纯签到完全背包。数据有点大。三个物品价值是互质的,我们把7,31,365乘起来,用n%(7*31......
  • 2022杭电多校第十场7、3、9、4
    1007EvenTreeSplit先考虑最简单的情况,如下图的边\((3,4)\),我们把这条边切掉,最后会留下一部分的点数为2,另一部分的点数依然是偶数。进一步思考可以知道,对于边\((u,v)\)......
  • hdu2022多校9
    A.ArithmeticSubsequence注意到等差数列加减乘除上同一个数仍是等差数列,这为分治提供了可能把所有数按奇偶分开,那么不会有跨过两边的等差数列。把偶数除以\(2\),奇数减......