HDU 6061

7 篇文章 0 订阅
4 篇文章 1 订阅

原题连接:
http://acm.hdu.edu.cn/showproblem.php?pid=6061

题目的意思可以理解为
给定多项式:

g(x)=i=0ncixi

计算多项式 g(xs)

<script type="math/tex; mode=display" id="MathJax-Element-3"></script>

推导:

g(xs)=i=0nci(xs)i=i=0nk=0i(ci(ik)xk(s)ik)=k=0ni=kn(ci(ik)xk(s)ik)=k=0nxki=kn(ci(ik)(s)ik)=k=0nxkk!i=kn(cii!(ik)!(s)ik)

<script type="math/tex; mode=display" id="MathJax-Element-5"></script>

令:

bk=cnk(nk)!

<script type="math/tex; mode=display" id="MathJax-Element-7"></script>

对于:

i=kn(cii!(ik)!(s)ik)=i=kn((s)ik(ik)!bni)

因为: ni+ik=nk
h=nk

ah=i=0h((s)ii!bhi)

可以快速计算a[]
从而得到新函数的系数形式。
#include <queue>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#define MAXN 400005
using namespace std;

typedef long long LL;
const LL P=998244353;
const LL G=3;

LL Pow(LL a,int b)
{
    LL tmp=1;
    while(b)
    {
        if(b&1)
            tmp=tmp*a%P;
        a=a*a%P;
        b>>=1;
    }
    return tmp;
}


void change(LL y[],int n)
{
    int b=n>>1,s=n-1;
    for(int i=1,j=n>>1;i<s;i++)
    {
        if(i<j)swap(y[i],y[j]);
        int k=b;
        while(j>=k)
        {
            j-=k;
            k>>=1;
        }
        j+=k;
    }
}

void NTT_(LL y[],int len,int on)
{
    change(y,len);
    for(int h=2;h<=len;h<<=1)
    {
        LL wh=Pow(G,(P-1)/h);
        if(on<0)wh=Pow(wh,P-2);
        for(int i=0;i<len;i+=h)
        {
            LL w=1;
            int r=h>>1;
            for(int k=i,s=r+i;k<s;k++)
            {
                LL u=y[k];
                LL t=w*y[k+r]%P;
                y[k]=u+t;   if(y[k]>=P)y[k]-=P;
                y[k+r]=u-t; if(y[k+r]<0) y[k+r]+=P;
                w=w*wh%P;
            }
        }
    }
    if(on<0)
    {
        LL I=Pow((LL)len,P-2);
        for(int i=0;i<len;i++) y[i]=y[i]*I%P;
    }
}


LL c[MAXN];
LL b[MAXN];
LL fac[MAXN];
LL Ivn[MAXN];

int main ()
{
    Ivn[0]=Ivn[1]=1;
    fac[0]=1;

    for(int i=1;i<MAXN;i++) fac[i]=fac[i-1]*i%P;

    for(int i=2;i<MAXN;i++) Ivn[i]=Pow(fac[i],P-2);

    int n;

    while(scanf("%d",&n)!=EOF)
    {

        n++;

        for(int i=0;i<n;i++)    scanf("%lld",c+i);

        for(int i=0;i<n;i++)    b[i]=c[n-i-1]*fac[n-i-1]%P;

        int m;

        LL S=0;

        int a;

        scanf("%d",&m);

        for(int i=0;i<m;i++)
        {

            scanf("%d",&a);
            S+=(LL)a;
            if(S>=P)S-=P;
        }

        for(int i=0 ; i<n ; i++) c[i]=Pow(P-S,i)*Ivn[i]%P;

        int len=1;

        while(len<(n<<1))len<<=1;

        for(int i=n;i<len;i++)  c[i]= b[i] = 0;

        NTT_(b,len,1);

        NTT_(c,len,1);

        for(int i=0;i<len;i++)  c[i]= c[i] * b[i] % P ;

        NTT_(c,len,-1);
        for(int i=0;i<n;i++) printf("%lld ",c[n-1-i] * Ivn[i] % P);

        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值