原题的价值 出题人:VFleaking hnoi2015 集训

来源:互联网 发布:易语言微信加好友源码 编辑:程序博客网 时间:2024/06/05 18:49

题目大意:

这里写图片描述
这里写图片描述
这里写图片描述

解题思路:

算法一(10分):

暴力枚举每条边是否选取,然后统计答案就行了,再次不赘述,可以通过测试点1。

算法二(40分):

观察456测试点,k=012,打表找规律或者各种乱七八糟的方法都可以找到公式,因为本人过于懒惰(愚蠢),所以不列出式子,让读者自己感受。

算法三(60分):

对于23测试点,这时候就只能推导公式了QAQ,首先对于无向图,我们考虑单独的一个节点u,u的度数dd[0,n1],我们考虑d=i时的情况,首先点u只能连出去n1条边,所以如果d=i,那么n1条边中有i条边是存在的,另外的是不存在的,那么贡献为(n1i)ik,然后再考虑剩下的与u不相关的(n1)(n2)2边,那么它们是可以任意选择的,所以此时对答案的贡献为2(n1)(n2)2,然后有n个点,所以ans=(n1i=0(n1i)ik)n2(n1)(n2)2,结合前面的找规律,可以得到60分,时间复杂度nlog2k

算法四(70分):

对于算法三,瓶颈在于计算n1i=0(n1i)ik,那么我们有什么办法可以把这个东西优化一下呢?有的,就是神奇的下降阶乘幂!!!!!!!!!首先显然有(n1i)ik(ikik,i0=0)=(nk1ik)(n1)k,所以我们如果有办法ik将表示成多个i的下阶幂形式就好了,我们令ik=kj=0(ajij),然后我们发现aj和第二类斯特林数很像(T^T,其实就是一毛一样啊)。然后我们翻看组合数学或者具体数学应该都可以找到这个式子ik=kj=0({kj}ij),然后就有ans=(n1i=0(kj=0(n1i){kj}ij))n2(n1)(n2)2
=(n1i=0(kj=0(nj1ij){kj}(n1)j))n2(n1)(n2)2
=(kj=0(n1i=0(nj1ij){kj}(n1)j))n2(n1)(n2)2
=(kj=0(2nj1{kj}(n1)j))n2(n1)(n2)2
这样就可以在k2时间内算出ans了。然后再结合算法三,就可以得到70分了。

算法五(100分):

观察算法四中的瓶颈,发现在求斯特林数{kj}这里,那么我们有没有什么办法优化呢?答案是有的!!!!!!!!!!!!
根据第二类斯特林数的模型意义(不知道的请上网查吧),根据容斥原理,我们有{kj}=1j!kt=0((1)t(jt)(jt)k)
=kt=0(1)tt!(jt)k(jt)!如果我们令多项式A(x)=kt=0(1)tt!xt
B(x)=kt=0tkt!xt,我们不难发现{kj}的各项就是A(x)B(x)的卷积,并且998244353是可以模意义下FFT的指数,果断上FFT,然后就用klog2k的时间算出了所有的{kj},然后就高高兴兴的AC了。

ps:不要问我怎么写FFT,我也不会T^T………

AC代码:

#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>#include <iostream>using namespace std;const long long Mod=998244353;long long n,K;long long S[100010]={0};long long N=1;long long a[300000]={0};long long b[300000]={0};long long c[300000]={0};long long ksm(long long a,long long k,long long MM){    long long o=1;    for(;k;)    {        if(k&1)            o=(long long)o*a%MM;        a=(long long)a*a%MM;        k>>=1;    }    return o;}void FFT(long long *A,int num,int flag){    for(int i=0;i<num;i++)    {        int p=0,s=i;        for(int j=(num>>1);j>=1;j>>=1)        {            p|=(s&1)*j;            s>>=1;        }        if(p>i) swap(A[i],A[p]);    }    for(int l=2;l<=num;l<<=1)    {        long long w;        if(flag==1)            w=ksm(3,(Mod-1)/l,Mod);        else        {            long long help=ksm(3,Mod-2,Mod);            w=ksm(help,(Mod-1)/l,Mod);        }        for(int i=0;i<num;i+=l)        {            long long wk=1;            for(int j=0;j<(l>>1);j++)            {                long long u=A[i+j],t=wk*A[i+j+(l>>1)]%Mod;                A[i+j]=(u+t)%Mod;                A[i+j+(l>>1)]=(u-t+Mod)%Mod;                wk=wk*w%Mod;            }        }    }    if(flag==-1)        for(int i=0;i<num;i++)            A[i]=A[i]*ksm(num,Mod-2,Mod)%Mod;    return;}int main(){    long long ans=0;    freopen("value.in","r",stdin);    freopen("value.out","w",stdout);    cin>>n>>K;    long long NI=1;    long long jiecheng=1;    int fh=1;    for(int i=0;i<=K;i++)    {        if(i==0)        {            a[i]=1;            b[i]=0;        }        else        {            jiecheng=jiecheng*ksm(i,Mod-2,Mod)%Mod;            a[i]=(fh*jiecheng+Mod)%Mod;            b[i]=ksm(i,K,Mod)*jiecheng%Mod;        }        fh*=-1;    }    N=1;    for(;N<K+K+1;N<<=1);    FFT(a,N,1);    FFT(b,N,1);    for(int i=0;i<N;i++)        c[i]=a[i]*b[i]%Mod;    FFT(c,N,-1);    for(long long i=0;i<=K;i++)    {        if(NI==0) break;        if(K==0)            c[0]=1;        ans+=c[i]*ksm(2,n-1-i,Mod)%Mod*NI%Mod;        NI=NI*(n-i-1)%Mod;        ans%=Mod;    }    ans=ans*n%Mod;    ans=ans*ksm(2,(n-1)*(n-2)/2,Mod)%Mod;    cout<<ans<<endl;    fclose(stdin);    fclose(stdout);    return 0;}
3 0
原创粉丝点击