2018SD省队集训R2 D3

本文针对两道算法竞赛题目提供了详细的解答过程。对于T1题目,通过DFS找出规律,并利用第二类斯特林数进行NTT变换求解;对于T2题目,则分别针对两个子任务给出了暴力拆解和二项式定理的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

T1

这里写图片描述

题解

首先我们写一个dfs然后打出表来,上oeis找规律。。。
找到一个

i=0aStirling2(a+1,i+1)(1)aiinai!∑i=0aStirling2(a+1,i+1)∗(−1)a−i∗in−a∗i!

把第二类斯特林数的求法带进去
i=0a(1)aii!inak=0i+1(1)kk!(i+1k)a+1(i+1k)!∑i=0a(−1)a−i∗i!∗in−a∑k=0i+1(−1)kk!(i+1−k)a+1(i+1−k)!

这样化完之后就是一个NTT的题目了

代码

#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int N=300005;
const int mod=998244353;
LL a[N],b[N],ans,mul[N],inv[N],invmul[N];int r[N],n,fn,A;
LL ksm(LL a,LL k)
{
    LL ans=1;
    for (;k;k>>=1,a=a*a%mod)
      if (k&1) ans=ans*a%mod;
    return ans;
}
void NTT(LL *a,int id)
{
    for (int i=0;i<n;i++)
      if (i<r[i]) swap(a[i],a[r[i]]);
    for (int k=1;k<n;k<<=1)
    {
        LL wn=ksm(3,(mod-1)/(k<<1));
        for (int i=0;i<n;i+=(k<<1))
        {
            LL w=1;
            for (int j=0;j<k;j++,w=w*wn%mod)
            {
                LL x=a[i+j],y=w*a[i+j+k]%mod;
                a[i+j]=(x+y)%mod; a[i+j+k]=(x-y+mod)%mod;
            }
        }
    }
    if (id==-1) reverse(a+1,a+n);
}
void init()
{
    mul[0]=1;
    for (int i=1;i<=n;i++) mul[i]=mul[i-1]*i%mod;
    inv[0]=inv[1]=1;
    for (int i=2;i<=n;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    invmul[0]=1;
    for (int i=1;i<=n;i++) invmul[i]=invmul[i-1]*inv[i]%mod;
    a[0]=1;b[0]=0;
    for (int i=1;i<=A+1;i++) 
    {
        a[i]=invmul[i];if (i&1) a[i]=-a[i];
        b[i]=invmul[i]*ksm(i,A+1)%mod;
    }
}
int main()
{
    freopen("per.in","r",stdin);
    freopen("per.out","w",stdout);
    scanf("%d%d",&fn,&A);
    int L=0;
    for (n=1;n<=(A+1)*2;n<<=1) L++;
    for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1) | ((i&1)<<L-1);
    init();
    NTT(a,1); NTT(b,1);
    for (int i=0;i<n;i++) a[i]=a[i]*b[i]%mod;
    NTT(a,-1);
    for (int i=0;i<=A;i++) 
    {
        LL t=mul[i]*ksm(i,fn-A)%mod*a[i+1]%mod*inv[n]%mod;
        if ((A-i)&1) t=-t;
        ans=(ans+t+mod)%mod;
    }
    printf("%lld",(ans+mod)%mod);
}

T2

这里写图片描述

题解

subtask1就是暴力拆解。
subtask2的操作是(x+1)^nm,是二项式定理,ck=Cknck=Cnk表示x^k的系数,那么从1开始递推可以求

代码

44pts(因为本人代码丑借用dalao代码QAQ

if (n<=2&&m<=2)
    {
        if (n>m) swap(n,m),swap(a,b);
        if (n==2)
        {
            LL a1a2=a[2],b1b2=b[2],ahe=a[1],bhe=b[1];
            h[0]=1; h[1]=ahe*bhe%mod;
            h[2]=(a1a2*bhe%mod*bhe%mod+b1b2*ahe%mod*ahe%mod)%mod;
            h[2]=(h[2]-2ll*a1a2%mod*b1b2%mod+mod)%mod;
            h[3]=a1a2*b1b2%mod*ahe%mod*bhe%mod;
            h[4]=a1a2*a1a2%mod*b1b2%mod*b1b2%mod;
            for (int i=0;i<k;i++) printf("%d ",h[i]);
        }
        else
        {
            h[0]=1; h[1]=1ll*a[1]*b[1]%mod;
            h[2]=a[1]*a[1]%mod*b[2]%mod;
            for (int i=0;i<k;i++) printf("%d ",h[i]);
        }
        return 0;
    }
    LL now=1,nm=n*m%mod,down=1;
    for (int i=0;i<k;i++)
    {
        printf("%lld ",now);
        now=now*nm%mod;
        now=now*ksm(down,mod-2)%mod;
        nm--; down++;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值