专项测试(数学4)

今天一不小心暴力没打完哈!

就被爆杀了,某某人比我高30分

这两天考的好难,我只能打暴力诶。

T1 传统题

这个??好像对我的组合能力有那么一点点的提升!!!

在考场上我想到了容斥,我是用至少形式转化的

然而至少形式使得容斥变得非常困难,需要考虑各种因素,而且可能会导致复杂度的升高。

于是我打了个小\(DP\)就走了

发现至少形式和至多形式可以互相转换,用总方案数减去至多为\(x\)的就是至少为\(x+1\)

那么我们可以容斥这个至多,这样的话,我们只需要选出几个超了的就好了

这题最重要的一点就是组合含义的转化

我们可以强行给一些式子赋予一个组合含义

有时候赋予之后就可能降低复杂度

这里的组合含义转化是依靠特殊点来转化的,染色也是很重要的一点

对于染色有一个技巧,如果要选出来几个数染成\(m-1\)中颜色,我们可以认为不染是第\(m\)种颜色,这样就不需要枚举选几个了

还有一个技巧,当一个东西不太好直接组合数求的时候,我们可以尝试枚举一些值

这样把一些东西分的清清楚楚就能使求解更加容易,我们可以后面在把一些枚举合并

分析复杂度也很重要,比如两个值之间有大小的限制!!!

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
const int N=3e5+5;
int n,m,mod,ans;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int jc[N],inv[N];
int C(int x,int y){return jc[x-1]*inv[y]%mod*inv[x-y]%mod;}
int pm[N],pmj[N];
int S(int t,int k){
    return (k*pmj[k-1]%mod*pm[n-t-k]+(n-t-k>0?(n-t-k)*pmj[k]%mod*pm[n-t-k-1]:0))%mod;
}
signed main(){
    n=read();m=read();mod=read();
    jc[0]=1;fo(i,1,n)jc[i]=jc[i-1]*i%mod;
    inv[0]=1;inv[n]=ksm(jc[n],mod-2);
    fu(i,n-1,1)inv[i]=inv[i+1]*(i+1)%mod;
    pm[0]=1;fo(i,1,n)pm[i]=pm[i-1]*m%mod;
    pmj[0]=1;fo(i,1,n)pmj[i]=pmj[i-1]*(m-1)%mod;
    fo(i,0,n-1)fo(k,0,n){
        if(i*k+k>n)break;
        int res=C(n-i*k,k)*S(i*k,k)%mod;
        if(k&1)ans=(ans-res+mod)%mod;
        else ans=(ans+res)%mod;
    }
    ans=(n*ksm(m,n)%mod-ans*m%mod+mod)%mod;
    printf("%lld",ans);
    return 0;
}

T2 生成树

这我考场上一直想\(meet\ in\ the\ middle\)

于是我没了,状压打了一年发现记重了......

想到是矩阵树定理,然而没想到怎么做

最后是设权值,然后用二维拉格朗日插系数

设绿色和蓝色边的权值分别为\(x,y\)

这样我们去求行列式,得到的权值就是一个二维多项式\(a_{i,j}x^iy^j\)的答案

而指数\(i,j\)就是绿色和蓝色边的数量,可以找到\(n^2\)个点值

拉格朗日二维和屌丝消元都行

\(x,y\)是变量,\(z\)是点值,拉格朗日二维的公式

\[\huge\sum\limits_{i=1}^{n^2}z_i\prod\limits_{j \ne i}\frac{x-x_j}{x_i-x_j}\prod\limits_{j \ne i}\frac{y-y_j}{y_i-y_j} \]

我懒了,写的屌丝消元

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
random_device you;
mt19937 pyt(you());
int rd(int l,int r){
    uniform_int_distribution<> ee(l,r);
    return ee(pyt);
}
const int mod=1e9+7;
const int N=45;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,m,g,b,ans;
int e[N][N][3];
struct matrix_tree{
    int a[N][N];
    void add(int x,int y,int v){
        a[x][x]=(a[x][x]+v)%mod;
        // a[y][y]=(a[y][y]+v)%mod;
        a[x][y]=(a[x][y]-v+mod)%mod;
        // a[y][x]=(a[y][x]-v+mod)%mod;
    }
    void init(int x,int y){
        memset(a,0,sizeof(a));
        fo(i,1,n)fo(j,1,n){
            add(i,j,1*e[i][j][0]);
            add(i,j,x*e[i][j][1]%mod);
            add(i,j,y*e[i][j][2]%mod);
        }
    }
    int ds(){
        int ret=1;
        fo(i,2,n){
            int mx=i;
            fo(j,i+1,n)if(a[j][i]>a[i][i]){
                fo(k,i,n)swap(a[i][k],a[j][k]);
                ret=(mod-ret)%mod;break;
            }
            fo(j,i+1,n){
                int iv=a[j][i]*ksm(a[i][i],mod-2)%mod;
                fo(k,i,n)a[j][k]=(a[j][k]-a[i][k]*iv%mod)%mod;
            }
        }
        fo(i,2,n)ret=ret*a[i][i]%mod;
        return (ret+mod)%mod;
    }
    int hls(int x,int y){
        init(x,y);return ds();
    }
}mt;
int a[N*N][N*N],x[N*N];
int id[N][N],cnt;
void gs(){
    fo(i,1,cnt){
        int mx=i;
        fo(j,i+1,cnt)if(a[j][i]>a[i][i]){
            fo(k,i,cnt+1)swap(a[i][k],a[j][k]);
            break;
        }
        if(!a[i][i])continue;
        fo(j,i+1,cnt){
            int iv=a[j][i]*ksm(a[i][i],mod-2)%mod;
            fo(k,i,cnt+1)a[j][k]=(a[j][k]-a[i][k]*iv%mod+mod)%mod;
        }
    }
    fu(i,cnt,1){
        int t=a[i][cnt+1];
        fo(j,i+1,cnt)t=(t-x[j]*a[i][j]%mod+mod)%mod;
        x[i]=t*ksm(a[i][i],mod-2)%mod;
    }
}
signed main(){
    n=read();m=read();g=read();b=read();
    fo(i,1,m){
        int x=read(),y=read(),z=read()-1;
        e[x][y][z]++;e[y][x][z]++;
    }
    fo(i,0,n-1)fo(j,0,n-1-i)id[i][j]=++cnt;
    fo(t,1,cnt){
        int x=rd(1,mod-1),y=rd(1,mod-1);
        fo(i,0,n-1){
            int now=ksm(x,i);
            fo(j,0,n-1-i)a[t][id[i][j]]=now,now=now*y%mod;
        }
        a[t][cnt+1]=mt.hls(x,y);
    }gs();
    fo(i,0,g)fo(j,0,b){
        ans=(ans+x[id[i][j]])%mod;
    }
    printf("%lld",ans);
    return 0;
}

T3 最短路径

这我只会树的分

要是基环的话......

基环树比树恶心一万倍......

分治!直接把环断开,不用倍长

发现中点两侧内部连边不可能绕一圈,于是这是第一个分治

要是跨越连边,比如说分成了四块,1和4连边,2和3连边

那就直接计算,这时我们发现好像1和3,2和4连边的话好像无法处理

其实我们把1和3拎出来合成一个块,就可以看做整块处理了,继续1和4,2和3连边就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')t=-1;ch=getchar();}
    while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
    return s*t;
}
const int inf=0x3f3f3f3f3f3f3f3f;
const int mod=998244353;
const int N=1<<18;
int ksm(int x,int y){
    int ret=1;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y>>=1;
    }return ret;
}
int n,m,an[N],ans;
struct NTT{
    int af[N],g[N],len,lim;
    void ntt(int *a,int lim){
        fo(i,0,lim-1)if(af[i]>i)swap(a[i],a[af[i]]);
        for(int t=lim>>1,d=1;d<lim;d<<=1,t>>=1)
            for(int i=0;i<lim;i+=(d<<1))
                fo(j,0,d-1){
                    int tmp=g[t*j]*a[i+j+d]%mod;
                    a[i+j+d]=(a[i+j]-tmp+mod)%mod;
                    a[i+j]=(a[i+j]+tmp)%mod;
                }
    }
    int a[N],b[N];
    void mul(int *s,int *t,int ls,int lt,int tp,int py){
        for(lim=1,len=0;lim<=ls+lt;lim<<=1,len++);
        fo(i,0,lim-1)af[i]=(af[i>>1]>>1)|((i&1)<<(len-1));
        fo(i,0,lim-1)a[i]=s[i],b[i]=t[i];
        g[0]=1;g[1]=ksm(3,(mod-1)/lim);
        fo(i,2,lim-1)g[i]=g[i-1]*g[1]%mod;
        ntt(a,lim);ntt(b,lim);
        g[0]=1;g[1]=ksm(g[1],mod-2);
        fo(i,2,lim-1)g[i]=g[i-1]*g[1]%mod;
        fo(i,0,lim-1)a[i]=a[i]*b[i]%mod;
        ntt(a,lim);int iv=ksm(lim,mod-2);
        fo(i,0,ls+lt)an[i+py]=(an[i+py]+a[i]*iv%mod*tp%mod)%mod;
    }
}nt;
struct E{int to,nxt;}e[N];
int head[N],rp=1;
void add_edg(int x,int y){e[++rp].to=y;e[rp].nxt=head[x];head[x]=rp;}
int siz[N],ms[N],mx,rt;bool vis[N],cir[N],vie[N];
void get_rt(int x,int f,int sz){
    siz[x]=1;ms[x]=0;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;if(y==f||vis[y]||cir[y])continue;
        get_rt(y,x,sz);siz[x]+=siz[y];ms[x]=max(ms[x],siz[y]);
    }
    ms[x]=max(ms[x],sz-siz[x]);if(mx>ms[x])rt=x,mx=ms[x];
}
int up[N],dw[N],mxd,md;
void get_dis(int x,int f,int d){
    dw[d]++;md=max(md,d);
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;if(y==f||vis[y]||cir[y])continue;
        get_dis(y,x,d+1);
    }
}
void sol(int x){mxd=0;up[0]=1;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;if(vis[y]||cir[y])continue;
        md=0;get_dis(y,x,1);nt.mul(dw,dw,md,md,mod-1,0);
        fo(j,0,md)up[j]=(up[j]+dw[j])%mod,dw[j]=0;mxd=max(mxd,md);
    }
    nt.mul(up,up,mxd,mxd,1,0);fo(i,0,mxd)up[i]=0;
}
void cal(int x,int sz){
    vis[x]=true;sol(x);
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;if(vis[y]||cir[y])continue;mx=inf;
        if(siz[y]<siz[x])get_rt(y,x,siz[y]),cal(rt,siz[y]);
        else get_rt(y,x,sz-siz[x]),cal(rt,sz-siz[x]);
    }
}
void spj1(){
    mx=inf;get_rt(1,0,n);cal(rt,n);
    int iv2=ksm(2,mod-2);
    fo(i,1,n)an[i]=an[i]*iv2%mod;
}
vector<int> son[N];
void work(int l1,int r1,int l2,int r2,int x){
    mxd=0;md=0;
    fo(i,l1,r1){
        fo(j,0,(int)son[i].size()-1)up[j+r1-i]+=son[i][j];
        mxd=max(mxd,(int)son[i].size()+r1-i);
    }
    fo(i,l2,r2){
        fo(j,0,(int)son[i].size()-1)dw[j+i-l2]+=son[i][j];
        md=max(md,(int)son[i].size()+i-l2);
    }
    nt.mul(up,dw,mxd,md,1,x);
    fo(i,0,mxd)up[i]=0;
    fo(i,0,md)dw[i]=0;
}
void sol1(int l,int r){
    if(l==r)return ;int mid=l+r>>1;
    work(l,mid,mid+1,r,1);
    sol1(l,mid);sol1(mid+1,r);
}
void sol2(int l1,int r1,int l2,int r2,int x){
    if(l1==r1||l2==r2)return work(l1,r1,l2,r2,x),void();
    int m1=l1+r1>>1,m2=l2+m1-l1;work(m1+1,r1,l2,m2,x);
    sol2(l1,m1,l2,m2,r1-m1+x);
    sol2(m1+1,r1,m2+1,r2,m2+1-l2+x);
}
int fa[N],c[N],cr;
void dfs_cir(int x,int f){
    vis[x]=true;fa[x]=f;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(vie[i])continue;vie[i]=vie[i^1]=true;
        if(y==f)continue;
        if(vis[y]){cir[x]=true;cir[fa[y]]=true;continue;}
        dfs_cir(y,x);cir[x]^=cir[y];
    }vis[x]=false;
    if(cir[x])c[++cr]=x;
}
void dfs_siz(int x,int f){
    siz[x]=1;
    for(int i=head[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==f||cir[y])continue;
        dfs_siz(y,x);siz[x]+=siz[y];
    }
}
void spj2(){
    dfs_cir(1,0);
    fo(i,1,cr){
        dfs_siz(c[i],0);
        md=0;get_dis(c[i],0,0);
        fo(j,0,md)son[i].push_back(dw[j]),dw[j]=0;
        mx=inf;cir[c[i]]=false;get_rt(c[i],0,siz[c[i]]);
        cal(rt,siz[c[i]]);cir[c[i]]=true;
    }
    int iv2=ksm(2,mod-2);
    fo(i,1,n)an[i]=an[i]*iv2%mod;
    int mid=cr>>1;
    sol1(1,mid);sol1(mid+1,cr);
    sol2(1,mid,mid+1,mid*2,1);
    sol2(mid+2,cr,1,cr-mid-1,1);
}
signed main(){
    n=read();m=read();
    bool flag=false;
    fo(i,1,n){
        int x=read(),y=read();
        if(x==y){flag=true;continue;}
        add_edg(x,y);add_edg(y,x);
    }
    if(flag)spj1();
    else spj2();
    fo(i,1,n)ans=(ans+an[i]*ksm(i,m))%mod;
    ans=ans*ksm(n*(n-1)/2%mod,mod-2)%mod;
    printf("%lld",ans);
}
posted @ 2022-01-08 21:10  fengwu2005  阅读(52)  评论(0编辑  收藏  举报