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

1 篇文章 0 订阅
题目大意:

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

解题思路:
算法一(10分):

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

算法二(40分):

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

算法三(60分):

对于 23 测试点,这时候就只能推导公式了QAQ,首先对于无向图,我们考虑单独的一个节点 u ,u的度数 d d[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
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值