WXHRound#13 场外被虐记

4 篇文章 0 订阅
2 篇文章 0 订阅

WXH太神了!T1还是找规律找出来的。。。T_T
Problem C.多项式

mi=1xiS,1inxiT,xi0 的解数

T,n,m109,n×TS,mn1000

题解:枚举前 n 项的和,即:
ans=Tx1=1Tx2=1...Txn=1(Sximn)

这是一个 mn 次多项式,即求:

ans=mnj=0ajTx1=1Tx2=1...Txn=1(xi)j

g(n,j)=Tx1=1Tx2=1...Txn=1(xi)j ,考虑倍增转移这个东西,即:

g(2n,j)=jk=0g(n,k)g(n,jk)(jk)

g(1,j)=Ti=1ik

所以这题就直接暴力插值出 g(1,j) ,然后倍增暴力卷积,然后暴力算多项式系数,复杂度 O((mn)2logn)

其实这题拿个伯努利数快速算 g(1,j) ,然后分治FFT+倍增FFT可以做到 log 的复杂度。。。但是鬼才写那玩意儿

#include<bits/stdc++.h>
#define mod 1000109107
#define maxn 1010
using namespace std;
typedef long long ll;
ll S,T,n,m;
int a[maxn],M,h[maxn],pri[maxn],psz,c[maxn],f[maxn],vis[maxn];
int g[maxn],p[maxn],C[maxn][maxn],pre[maxn],suf[maxn],fac[maxn],inv[maxn];

int qpow(int a,int b){
    int ans=1;
    for(;b;b>>=1,a=1ll*a*a%mod)
        if(b&1)ans=1ll*ans*a%mod;
    return ans;
}
int cal(int x){
    if(x==0)return T;
    f[1]=1;
    int ans=0,D=x+2;
    for(int i=2;i<=D;++i)
        if(!vis[i])f[i]=qpow(i,x);
        else f[i]=1ll*f[i/c[i]]*f[c[i]]%mod;
    if(T<=D){
        for(int i=1;i<=T;++i)
            ans=(ans+f[i])%mod;
        return ans;
    }
    pre[0]=suf[D+1]=1;
    for(int i=1;i<=D;++i)pre[i]=1ll*pre[i-1]*(T-i+mod)%mod;
    for(int i=D;i>=1;--i)suf[i]=1ll*suf[i+1]*(T-i+mod)%mod;
    for(int i=1,sum=0;i<=D;++i){
        sum=(sum+f[i])%mod;
        ans=(ans+1ll*inv[i-1]*inv[D-i]%mod*(D-i&1?mod-1:1)%mod*pre[i-1]%mod*suf[i+1]%mod*sum)%mod;
    }
    return ans;
}
void mul(int g[],int h[],int ans[]){
    for(int i=0;i<=M;++i)p[i]=0;
    for(int i=0;i<=M;++i)if(g[i])
        for(int j=0;i+j<=M;++j)if(h[j])
            p[i+j]=(p[i+j]+1ll*g[i]*h[j]%mod*C[i+j][i])%mod;
    for(int i=0;i<=M;++i)ans[i]=p[i];
}
void sol(ll n){
    if(n==0){
        g[0]=1;
        return ;
    }
    if(n==1){
        for(int i=0;i<=M;++i)g[i]=h[i];
        return ;
    }
    sol(n/2);
    mul(g,g,g);
    if(n&1)mul(g,h,g);
}
int main(){
    cin>>S>>T>>n>>m,M=m-n;
    a[0]=1,S%=mod,T%=mod;
    for(int i=2;i<=M+1;++i){
        if(!vis[i])pri[++psz]=i;
        for(int j=1,A;j<=psz&&i*pri[j]<=M+1;++j){
            vis[A=i*pri[j]]=1,c[A]=pri[j];
            if(i%pri[j]==0)break;
        }
    }
    fac[0]=inv[0]=1;
    for(int i=1;i<=M+1;++i)fac[i]=1ll*fac[i-1]*i%mod;
    inv[M+1]=qpow(fac[M+1],mod-2);
    for(int i=M;i>=1;--i)inv[i]=1ll*inv[i+1]*(i+1)%mod;
    for(int i=1;i<=M;++i)
        for(int j=i-1;j>=0;--j)
            a[j+1]=(a[j+1]+mod-a[j])%mod,
            a[j]=1ll*a[j]*(S-i+1+mod)%mod;
//  for(int i=0;i<=M;++i)printf("{%d}",a[i]);puts("");
    for(int i=0;i<=M;++i)h[i]=cal(i);//,printf("{%d}",h[i]);
    for(int i=0;i<=M+1;++i)
        for(int j=*C[i]=1;j<=i;++j)
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    sol(n);
    int ans=0;
    for(int i=0;i<=M;++i)
        ans=(ans+1ll*g[i]*a[i])%mod;
    printf("%d\n",1ll*ans*inv[M]%mod);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值