zoukankan      html  css  js  c++  java
  • 【LOJ6059】「2017 山东一轮集训 Day1」Sum(倍增优化数位DP+NTT)

    点此看题面

    大致题意: 对于(i=1sim m),分别求出有多少个(n)位数,满足它是(p)的倍数,且各位之和小于等于(i)

    暴力数位(DP)

    不看数据范围,这道题显然就是个数位(DP)

    考虑设(f_{i,j,k})表示考虑了(i)位,模(p)(j),且数位和为(k)的方案数,转移只要枚举填(0sim9)即可,非常显然。

    但是,(nle10^9)。。。

    对于这种数据范围,我们考虑倍增优化(DP)

    倍增

    考虑从(f_n)(f_{n+1}),和暴力(DP)一样,只要枚举填(0sim9)即可。

    然后考虑从(f_n)(f_{2n}),我们可以枚举两部分各自模(p)的余数(x,y),转移如下:

    [f_{2n,(x imes 10^n+y)\%p,u+v}=f_{n,x,u} imes f_{n,y,v} ]

    这个式子最后一维明显是一个卷积形式,因此可以(NTT)优化。

    于是这道题就做完了,具体实现详见代码。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define M 1000
    #define X 998244353
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    using namespace std;
    int n,p,m,tn,f[50][M+5],tmp[50][M+5];
    I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    namespace Poly//多项式
    {
    	#define PR 3
    	#define IPR 332748118
    	int P,L,Inv,A[M<<2],B[M<<2],R[M<<2];I void Init()//初始化,因为每次卷积数组长度相同
    	{
    		P=1,L=0;W(P<=(m<<1)) P<<=1,++L;Inv=QP(P,X-2);
    		for(RI i=0;i^P;++i) R[i]=((R[i>>1]>>1)|((i&1)<<L-1));
    	}
    	I void NTT(int *s,CI p)//NTT
    	{
    		RI i,j,k,x,y,U,S;for(i=0;i^P;++i) i<R[i]&&(x=s[i],s[i]=s[R[i]],s[R[i]]=x);
    		for(i=1;i^P;i<<=1) for(U=QP(p,X/(i<<1)),j=0;j^P;j+=i<<1) for(S=1,k=0;k^i;
    			S=1LL*S*U%X,++k) s[j+k]=((x=s[j+k])+(y=1LL*S*s[i+j+k]%X))%X,s[i+j+k]=(x-y+X)%X;
    	}
    	I void Mul(int *a,int *b,int *res)//多项式乘法
    	{
    		RI i;memset(A,0,sizeof(int)*P),memset(B,0,sizeof(int)*P);
    		for(i=0;i<=m;++i) A[i]=a[i],B[i]=b[i];
    		for(NTT(A,PR),NTT(B,PR),i=0;i^P;++i) A[i]=1LL*A[i]*B[i]%X;
    		for(NTT(A,IPR),i=0;i<=m;++i) res[i]=(1LL*A[i]*Inv+res[i])%X;
    	}
    }
    I void Solve(CI x)//倍增优化DP,其实我写得类似于一个快速幂的过程
    {
    	if(!x) return (void)(f[0][0]=tn=1);Solve(x>>1);
    	RI i,j,k;for(i=0;i^p;++i) for(j=0;j^p;++j) Poly::Mul(f[i],f[j],tmp[(tn*i+j)%p]);//n->2n
    	for(i=0;i^p;++i) for(j=0;j<=m;++j) f[i][j]=tmp[i][j],tmp[i][j]=0;
    	if(x&1)
    	{
    		for(i=0;i^p;++i) for(j=0;j<=m;++j)//n->n+1
    			for(k=0;k<=9&&j+k<=m;++k) Inc(tmp[(10*i+k)%p][j+k],f[i][j]);//枚举填的数暴力DP
    		for(i=0;i^p;++i) for(j=0;j<=m;++j) f[i][j]=tmp[i][j],tmp[i][j]=0;
    	}
    	tn=tn*tn%p,x&1&&(tn=tn*10%p);//维护10^n
    }
    int main()
    {
    	scanf("%d%d%d",&n,&p,&m),Poly::Init(),Solve(n);
    	for(RI i=0,t=0;i<=m;++i) Inc(t,f[0][i]),printf("%d%c",t," 
    "[i==m]);return 0;//注意做前缀和
    }
    
  • 相关阅读:
    移动应用跨平台之旅
    ReactNative之坑爹的在线安装
    关于拆箱装箱引发的类型转换报错
    Unity HDR (高动态范围 )
    Instruments如何看Mono内存分配
    Unity编辑器崩溃大全
    Unity3D获取手机存储空间
    关于构建AssetBundle哈希冲突的问题
    关于UnityWebRequest的超时讨论
    Wwise音频插件介绍
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/LOJ6059.html
Copyright © 2011-2022 走看看