• CF1096G Lucky Tickets


    X.CF1096G Lucky Tickets

    这题一个NTT快速幂的形式就非常明显了。直接构建一个函数(g(x)=[xin ext{给出的k个数码}])。则我们要求的就是(sumlimits_{i=0}^{infty}(g^{n/2}(i))^2)。由于模数是(998244353),因此采取NTT会比较轻松。

    但是,如果你直接打一份暴力NTT快速幂上去,是会T的。怎么办呢?

    由于(g^1)的范围很小(([0,9])),因此如果我们一直总是把NTT的数组长度设为与(n)同级的长度的话,就会让前面很多东西都是在空跑。因此,我们可以在快速幂的过程中,动态修改数组长度。假如现在快速幂到(g^x),我们就令数组长度为一个与(x)同级的长度,当快速幂到(g^{2x})时,再令数组长度为一个与(2x)同级的长度。这样,原本复杂度约为(nlog^2n),同时有大常数。现在,复杂度约为(sum_{i=1}^{log n}2^ilog{2^i}=sum_{i=1}^{log n}i*2^iapprox nlog nloglog n)(尽管常数仍然巨大)。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int mod=998244353;
    const int G=3;
    int n,bs[1<<20],lim=1,lg,m,invlim,rev[1<<20],f[1<<20],g[1<<20],qaq[1<<20],res;
    inline int pov(int x,int y){
    	int res=1;
    	for(;y;x=(1ll*x*x)%mod,y>>=1)if(y&1)res=(1ll*res*x)%mod;
    	return res;
    }
    inline void NTT(int *a,int tp){
    	for(register int i=0;i<lim;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(register int md=1;md<lim;md<<=1){
    		register int rt=pov(G,(mod-1)/(md<<1));
    		if(tp==-1)rt=pov(rt,mod-2);
    		for(register int stp=md<<1,pos=0;pos<lim;pos+=stp){
    			register int w=1;
    			for(register int i=0;i<md;i++,w=(1ll*w*rt)%mod){
    				register int x=a[pos+i],y=(1ll*w*a[pos+md+i])%mod;
    				a[pos+i]=(x+y)%mod;
    				a[pos+md+i]=(x-y+mod)%mod;
    			}
    		}
    	}
    }
    inline void mul(int *a,int *b,int *c){
    	for(register int i=0;i<lim;i++)f[i]=a[i],g[i]=b[i];
    	NTT(f,1),NTT(g,1);
    	for(register int i=0;i<lim;i++)f[i]=(1ll*f[i]*g[i])%mod;
    	NTT(f,-1);
    	for(register int i=0;i<lim;i++)c[i]=(1ll*f[i]*invlim)%mod;
    }
    inline void ksm(int x){
    	if(x==1){while(lim<x*10)lim<<=1,lg++;for(register int i=0;i<10;i++)qaq[i]=bs[i];return;}
    	ksm(x>>1);
    	while(lim<x*10)lim<<=1,lg++;
    	invlim=pov(lim,mod-2);
    	for(register int i=1;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
    	mul(qaq,qaq,qaq);
    	if(x&1)mul(qaq,bs,qaq);
    }
    int main(){
    	scanf("%d%d",&n,&m),n>>=1;
    	for(register int i=0,x;i<m;i++)scanf("%d",&x),bs[x]++;
    	ksm(n);
    	for(register int i=0;i<lim;i++)res=(1ll*qaq[i]*qaq[i]%mod+res)%mod;
    	printf("%d
    ",res);
    	return 0;
    }
    
  • 相关阅读:
    zlib 用了很多次,这次记下来
    boost 1.53 比1.52 ASIO bug 修正
    64位汇编
    js C++
    这个split 不错 我喜欢的
    布6月26日至28日将在旧金山召开2013年Build大会
    asio同步模式和异步模式
    vc6 编译boost
    windows 编译mongodb 2.4
    ajaxToolKit中 的折叠面板用法Accordion
  • 原文地址:https://www.cnblogs.com/Troverld/p/12772267.html
Copyright © 2020-2023  润新知