码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-04-01 09:44:52      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:

技术分享
技术分享
技术分享

解题思路:

算法一(10)

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

算法二(40)

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

算法三(60)

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

算法四(70)

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

算法五(100):

观察算法四中的瓶颈,发现在求斯特林数{kj}这里,那么我们有没有什么办法优化呢?答案是有的!!!!!!!!!!!!
根据第二类斯特林数的模型意义(不知道的请上网查吧),根据容斥原理,我们有{kj}=1j!?kt=0((?1)t?(jt)?(j?t)k)
=kt=0(?1)tt!?(j?t)k(j?t)!如果我们令多项式A(x)=kt=0(?1)tt!?xt
B(x)=kt=0tkt!,我们不难发现{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;
}

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

标签:

原文地址:http://blog.csdn.net/qq_21995319/article/details/44785921

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!