Interesting Series(分治fft模板)

Interesting Series

题意:

定义 f 1 = 1 , f n = a × f n − 1 + 1 ( n ≥ 2 ) f_1=1,f_n=a\times f_{n-1}+1(n\geq 2) f1=1,fn=a×fn1+1(n2)
输入 n ( 1 e 5 ) , a ( 1 e 3 ) , q ( 1 e 5 ) n(1e5),a(1e3),q(1e5) n(1e5),a(1e3),q(1e5)
接下来输入 s 1 , s 2 , … , s n ( 1 e 9 ) s_1,s_2,\dots,s_n(1e9) s1,s2,,sn(1e9)表示集合中的元素;
接下来 q 行 q行 q
每行一个元素 k ( 1 ≤ k ≤ n ) k(1\leq k\leq n) k(1kn),表示一个询问,求 ∑ v a l u e s ( s ) \sum values(s) values(s)( s s s表示大小为 k k k的子集, v a l u e s ( s ) = f s u m ( s ) values(s)=f_{sum(s)} values(s)=fsum(s), s u m ( s ) sum(s) sum(s)表示集合元素和)。

题解:

很容易得到 f n = a n − 1 a − 1 f_n=\frac {a^n-1}{a-1} fn=a1an1
构造母函数 ( a s 1 x + 1 ) × ( a s 2 x + 1 ) × ⋯ × ( a s n x + 1 ) (a^{s_1}x+1)\times(a^{s_2}x+1)\times\dots\times(a^{s_n}x+1) (as1x+1)×(as2x+1)××(asnx+1)
这样得到 x k x^k xk的系数表示选了 k k k个元素的 ∑ a h e \sum a^{he} ahe然后再把它减 C n k C_{n}^{k} Cnk后除以 a − 1 a-1 a1就好。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
const int N=1e5+9;
#define pi acos(-1.0)
#define cp complex<double>
int n,a,q;
const int mod=1e5+3;
int s[N];
vector<int>ans[N<<2];
cp b[N<<2],c[N<<2];
int frac[N],inv[N];
void init(){
    frac[0]=frac[1]=inv[0]=inv[1]=1;
    for(int i=2;i<mod;i++)frac[i]=1ll*frac[i-1]*i%mod,inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=2;i<mod;i++)inv[i]=1ll*inv[i-1]*inv[i]%mod;
}
inline int C(int n,int k){
    return 1ll*frac[n]*inv[k]%mod*inv[n-k]%mod;
}
int poww(int a,int b,int c){
    int ans=1,base=a;
    while(b){
        if(b&1)ans=1ll*ans*base%c;
        base=1ll*base*base%c;
        b>>=1;
    }
    return ans;
}
int rev[N<<2];
int limit,lim;
void fft(cp *a,int type){
    for(int i=0;i<limit;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    for(int mid=1;mid<limit;mid<<=1){
        double alpha=type*pi/mid;
        for(int i=0;i<limit;i+=mid*2){
            for(int j=0;j<mid;j++){
                cp w(cos(alpha*j),sin(alpha*j));
                cp x=a[i+j],y=a[i+j+mid]*w;
                a[i+j]=x+y,a[i+j+mid]=x-y;
            }
        }
    }
    if(type==-1){
        for(int i=0;i<limit;i++){
            a[i]=cp((long long)(a[i].real()/limit+0.5)%mod,0);
        }
    }
}
void calc(cp *a,cp *b){
    fft(a,1),fft(b,1);
    for(int i=0;i<limit;i++)a[i]*=b[i];
    fft(a,-1);
}
/*
void print(cp *a){
    for(int i=0;i<10;i++)cout<<int(a[i].real()+0.5)<<" ";cout<<endl;
}*/
void solve(int p,int l,int r){
    if(l==r){
        ans[p].push_back(1);
        ans[p].push_back(s[l]);
        return;
    }
    int mid=(l+r)>>1,len=(r-l+2);
    solve(ls(p),l,mid),solve(rs(p),mid+1,r);
    limit=1,lim=0;
    while(limit<=len)limit<<=1,lim++;
    for(int i=0;i<limit;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lim-1)),b[i]=c[i]=cp(0,0);
    for(int i=0;i<ans[ls(p)].size();i++)c[i]=cp(ans[ls(p)][i],0);
    for(int i=0;i<ans[rs(p)].size();i++)b[i]=cp(ans[rs(p)][i],0);
    calc(b,c);
    for(int i=0;i<limit;i++)ans[p].push_back(int(b[i].real()+0.5));
}
int d[N];
int main(){
    //freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
    init();
    scanf("%d%d%d",&n,&a,&q);
    for(int i=1;i<=n;i++)scanf("%d",&s[i]),s[i]=poww(a,s[i],mod);
    solve(1,1,n);
    int inva=poww(a-1,mod-2,mod);
    for(int i=1;i<=n;i++)d[i]=((long long)(ans[1][i])%mod+mod-C(n,i))*inva%mod;
    while(q--){
        int t;
        scanf("%d",&t);
        printf("%d\n",d[t]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值