51nod 1348 乘积之和

用(r-l+2)维向量f[l,r]表示区间[l,r]内选i个数(0<=i<=r-l+1)相乘的所有方案之和,可以发现f[l,r]=f[l,m]*f[m+1,r],题目模数100003较小,每次卷积后答案上界大约为1e16,用ntt在两个1e9左右的模数下计算后CRT合并即可,复杂度为O(nlog2n),要注意常数优化

#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long i64;
int _(){
    int x=0,f=1,c=getchar();
    while(c<48)c==‘-‘&&(f=-1),c=getchar();
    while(c>47)x=x*10+c-48,c=getchar();
    return x*f;
}
int pow(int a,int n,int p){
    int v=1;
    for(;n;n>>=1){
        if(n&1)v=i64(v)*a%p;
        a=i64(a)*a%p;
    }
    return v;
}
i64 mul(i64 a,i64 b,i64 p){
    i64 s=0;
    a%=p;b%=p;
    while(b){
        if(b&1)(s+=a)%=p;
        (a<<=1)%=p;
        b>>=1;
    }
    return s;
}
int N,X,r[262144];
template<const int p,const int g>
void ntt(int*a,int t){
    for(int i=0;i<N;++i)if(i>r[i])std::swap(a[i],a[r[i]]);
    for(int i=1;i<N;i<<=1){
        int w=pow(g,(t*(p-1)/(i*2)+p-1),p);
        for(int j=0;j<N;j+=i<<1){
            int e=1,*b=a+j,*c=b+i;
            for(int k=0;k<i;++k,e=i64(e)*w%p){
                int x=b[k],y=c[k]*i64(e)%p;
                b[k]=(x+y)%p;
                c[k]=(x-y+p)%p;
            }
        }
    }
    if(t==-1){
        i64 I=pow(N,p-2,p);
        for(int i=0;i<N;++i)a[i]=a[i]*I%p;
    }
}
int n,q,v0[50007],mem[65536*20+7],*mp=mem,vs[4][65536+7];
const int p1=998244353,g1=3,p2=950009857,g2=7;
const i64 m1=i64(p1)*pow(p1,p2-2,p2),m2=i64(p2)*pow(p2,p1-2,p1),ps=i64(p1)*p2;
int*calc(int L,int R){
    int*pos=mp;mp+=R-L+1;
    if(L==R){
        *pos=v0[L];
        return pos;
    }
    int M=L+R>>1;
    int*lp=calc(L,M)-1;
    int*rp=calc(M+1,R)-1;
    for(N=2,X=0;N<R-L+2;N<<=1,++X);
    if(R-L+1<=16){
        for(int i=0;i<2;++i)memset(vs[i],0,N*sizeof(int)),vs[i][0]=1;
        for(int i=1;i<=M-L+1;++i)vs[0][i]=lp[i];
        for(int i=1;i<=R-M;++i)vs[1][i]=rp[i];
        for(int i=1;i<=R-L+1;++i){
            for(int j=0;j<=i;++j)pos[i-1]=(pos[i-1]+i64(vs[0][j])*vs[1][i-j])%100003;
        }
        return pos;
    }
    for(int i=1;i<N;++i)r[i]=r[i>>1]>>1|(i&1)<<X;
    for(int i=0;i<4;++i)memset(vs[i],0,N*sizeof(int)),vs[i][0]=1;
    for(int i=1;i<=M-L+1;++i)vs[0][i]=vs[1][i]=lp[i];
    for(int i=1;i<=R-M;++i)vs[2][i]=vs[3][i]=rp[i];
    ntt<p1,g1>(vs[0],1);
    ntt<p1,g1>(vs[2],1);
    ntt<p2,g2>(vs[1],1);
    ntt<p2,g2>(vs[3],1);
    for(int i=0;i<N;++i)vs[0][i]=i64(vs[0][i])*vs[2][i]%p1;
    for(int i=0;i<N;++i)vs[1][i]=i64(vs[1][i])*vs[3][i]%p2;
    ntt<p1,g1>(vs[0],-1);
    ntt<p2,g2>(vs[1],-1);
    for(int i=1;i<=R-L+1;++i)pos[i-1]=(mul(m2,vs[0][i],ps)+mul(m1,vs[1][i],ps))%ps%100003;
    return pos;
}
int main(){
    n=_();q=_();
    for(int i=1;i<=n;++i)v0[i]=_();
    int*ans=calc(1,n)-1;
    while(q--)printf("%d\n",ans[_()]);
    return 0;
}
时间: 2024-12-10 05:30:44

51nod 1348 乘积之和的相关文章

51nod 1348 乘积之和 分治 + fft

给出由N个正整数组成的数组A,有Q次查询,每个查询包含一个整数K,从数组A中任选K个(K <= N)把他们乘在一起得到一个乘积.求所有不同的方案得到的乘积之和,由于结果巨大,输出Mod 100003的结果即可.例如:1 2 3,从中任选1个共3种方法,{1} {2} {3},和为6.从中任选2个共3种方法,{1 2} {1 3} {2 3},和为2 + 3 + 6 = 11. 预处理 + O(1)回答 很容易想到用分治来做,这样在分治过程中需要一个dp,这个dp递推式是O(n^2)的, 所以复杂

【51nod1348】乘积之和

Description 给出由N个正整数组成的数组A,有Q次查询,每个查询包含一个整数K,从数组A中任选K个(K <= N)把他们乘在一起得到一个乘积.求所有不同的方案得到的乘积之和,由于结果巨大,输出Mod 100003的结果即可.例如:1 2 3,从中任选1个共3种方法,{1} {2} {3},和为6.从中任选2个共3种方法,{1 2} {1 3} {2 3},和为2 + 3 + 6 = 11. Solution 用\(f_{l,r,x}(0\leq x\leq r-l+1)\)表示区间\(

51nod 1220 约数之和(杜教筛 + 推推推推推公式)

题意 给出\(n(1\leq n \leq 10^9)\),求\(\sum_{i=1}^n\sum_{j=1}^n\sigma(ij)\),其中\(\sigma(n)\)表示\(n\)的约数之和. balabala 交了两道杜教筛的的板子题(51nod 1239, 1244)就看到了这题,然后不会搞,然后看题解看了一天一夜终于彻底搞明白一发A掉了...感觉学到了很多,写个博客整理一下,如有错请指出. 技能需求 数论函数与线性筛 莫比乌斯反演(也可以当成容斥去理解) 狄利克雷卷积 杜教筛 强大的数

51NOD 1110 距离之和最小 V3(中位数 + 技巧)

传送门 X轴上有N个点,每个点除了包括一个位置数据X[i],还包括一个权值W[i].该点到其他点的带权距离 = 实际距离 * 权值.求X轴上一点使它到这N个点的带权距离之和最小,输出这个最小的带权距离之和. Input 第1行:点的数量N.(2 <= N <= 10000) 第2 - N + 1行:每行2个数,中间用空格分隔,分别是点的位置及权值.(-10^5 <= X[i] <= 10^5,1 <= W[i] <= 10^5) Output 输出最小的带权距离之和.

51NOD 1108 距离之和最小 V2(中位数 + 化整为分)

传送门 三维空间上有N个点, 求一个点使它到这N个点的曼哈顿距离之和最小,输出这个最小的距离之和. 点(x1,y1,z1)到(x2,y2,z2)的曼哈顿距离就是|x1-x2| + |y1-y2| + |z1-z2|.即3维坐标差的绝对值之和. Input 第1行:点的数量N.(2 <= N <= 10000) 第2 - N + 1行:每行3个整数,中间用空格分隔,表示点的位置.(-10^9 <= X[i], Y[i], Z[i] <= 10^9) Output 输出最小曼哈顿距离之

51Nod 1110 距离之和最小 V3 中位数 思维

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 X轴上有N个点,每个点除了包括一个位置数据X[i],还包括一个权值W[i].点P到点P[i]的带权距离 = 实际距离 * P[i]的权值.求X轴上一点使它到这N个点的带权距离之和最小,输出这个最小的带权距离之和.Input第1行:点的数量N.(2 <= N <= 10000)第2 - N + 1行:每行2个数,中间用空格分隔,分别是点的位置及权值.(-10^5 <= X[i] <= 10^5,1 &

51nod 1096 距离之和最小【中位数】

1096 距离之和最小 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  关注 X轴上有N个点,求X轴上一点使它到这N个点的距离之和最小,输出这个最小的距离之和. Input 第1行:点的数量N.(2 <= N <= 10000) 第2 - N + 1行:点的位置.(-10^9 <= P[i] <= 10^9) Output 输出最小距离之和 Input示例 5 -1 -3 0 7 9 Output示例 20[分析]:注意LL,距离abs

【学术篇】51nod 1238 最小公倍数之和

这是一道杜教筛的入(du)门(liu)题目... 题目大意 求 \[ \sum_{i=1}^n\sum_{j=1}^nlcm(i,j) \] 一看就是辣鸡反演一类的题目, 那就化式子呗.. \[ \sum_{i=1}^n\sum_{j=1}^nlcm(i,j) \=\sum_{i=1}^n\sum_{j=1}^n\frac{ij}{gcd(i,j)} \=\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^n\frac{ij}k[gcd(i,j)=k] \=\sum_{k=1}

51nod 1110 距离之和最小V3

X轴上有N个点,每个点除了包括一个位置数据X[i],还包括一个权值W[i].点P到点P[i]的带权距离 = 实际距离 * P[i]的权值.求X轴上一点使它到这N个点的带权距离之和最小,输出这个最小的带权距离之和. Input 第1行:点的数量N.(2 <= N <= 10000) 第2 - N + 1行:每行2个数,中间用空格分隔,分别是点的位置及权值.(-10^5 <= X[i] <= 10^5,1 <= W[i] <= 10^5) Output 输出最小的带权距离之