玲珑杯 1160
来源:互联网 发布:php 数组长度 编辑:程序博客网 时间:2024/05/19 12:14
题意,在n本书中要拿k本书的倍数的方案,每本书都不同,一本都不拿也算一种方案
开始以为是直接求C(n,0)+C(n,k)+C(n,2k)…
求不出来 orz
看了题解后 问了yql大佬
先是可以得到一个递推式
F[i][j]:表示前i本书,拿j本的方案
F[i][j]=F[i-1][j]+F[i-1][j-1]
因为j比较大,我们可以用滚动数组,j=j% k
然后可以得到
答案就是f[n][0],我们只用求第一行就行了。
设,A为图中第一个矩阵,A矩阵是k*k,如果朴素求第一行的话,时间复杂度为k*k*logn,超时gg… 然后我们发现这个可以用NTT来加速
注意到A是循环矩阵
(什么是循环矩阵?类似于
如果A=
则A*A的第一行为(a1*a1+a2*a3+a3*a2 , a1*a2+a2*a1+a3*a3, a1*a3+a2*a2+a3*a1)
这个就是
卷积就可以用NTT了~用NTT的总时间复杂度为O(k*logn*logk),当k为3e4时,为1e7,但k为3e5时就会超时。因为当k>3e4时,k只能为2的幂。一般去长度为k的循环卷积,肯定做的是>2k的FFT,来保证不会出错,但是如果k是2的次幂,就可以直接做长度为k的FFT,就可以直接变成点值之后快速幂。(yql教的:>)当k为2的幂次,时间大概是O(k*logn)
<从这个题中学到了很多,感谢yql~>
<基本上是yql的代码….>
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <cmath>#include <vector>using namespace std;const int maxn = 600005;#define mod 998244353#define ll long longint A[maxn],B[maxn],Ans[maxn],X[maxn];ll n;int k;int gg=3;int fexp(int x,int p){int ans=1;for(;p;p>>=1,x=1LL*x*x%mod)if(p&1)ans=1LL*ans*x%mod;return ans;}void NTT(int *a,int f,int k){ for(int i=0,j=0;i<k;i++){ if(i>j)swap(a[i],a[j]); for(int l=k>>1;(j^=l)<l;l>>=1); } for(int i=1;i<k;i<<=1) { int w=fexp(gg,(f*(mod-1)/(i<<1)+mod-1)%(mod-1)); for(int j=0;j<k;j+=i<<1){int e=1; for(int k=0;k<i;k++,e=1LL*e*w%mod){int x,y; x=a[j+k];y=1LL*a[j+k+i]*e%mod; a[j+k]=(x+y)%mod;a[j+k+i]=(x-y+mod)%mod; } } } if(f==-1){ int _inv=fexp(k,mod-2); for(int i=0;i<k;i++)a[i]=1LL*a[i]*_inv%mod; }}void Work(){ if((k&(-k))==k) { NTT(X,1,k); NTT(Ans,1,k); for(;n;n>>=1) { if(n&1) for(int i=0;i<k;i++) Ans[i]=1LL*Ans[i]*X[i]%mod; for(int i=0;i<k;i++) X[i]=1LL*X[i]*X[i]%mod; } NTT(Ans,-1,k); } else { int t; for(t=1;t<=(k*2);t<<=1); for(;n;n>>=1) { if(n&1){ for(int i=0;i<t;i++) A[i]=B[i]=0; for(int i=0;i<k;i++) A[i]=Ans[i],B[i]=X[i]; NTT(A,1,t),NTT(B,1,t); for(int i=0;i<t;i++) A[i]=1LL*A[i]*B[i]%mod; NTT(A,-1,t); for(int i=0;i<t;i++) Ans[i]=0; for(int i=0;i<t;i++) Ans[i%k]=(Ans[i%k]+A[i])%mod; } for(int i=0;i<t;i++) A[i]=B[i]=0; for(int i=0;i<k;i++) A[i]=X[i]; NTT(A,1,t); for(int i=0;i<t;i++) A[i]=1LL*A[i]*A[i]%mod; NTT(A,-1,t); for(int i=0;i<k;i++) X[i]=0; for(int i=0;i<t;i++) X[i%k]=(X[i%k]+A[i])%mod; } } printf("%d\n",Ans[0]);}void init(){ Ans[0]=1;X[0]++,X[k-1]++;}int main(){ scanf("%lld %d",&n,&k); init(); Work(); return 0;}
- 玲珑杯 1160
- 玲珑杯
- 【玲珑杯 1010 Alarm】
- 玲珑杯 1010 - Alarm
- 玲珑杯-【 chess play】
- 玲珑杯-【See car】
- 玲珑杯-1065-思维
- 玲珑杯-1058-dfs
- 玲珑杯 C -- Coco
- 玲珑杯-1071【思维】
- 玲珑杯-Boring Game
- “玲珑杯”Round #11
- 玲珑杯 1101
- 玲珑杯-base64加密
- 玲珑杯 1125
- 玲珑杯 1131
- 玲珑杯 1121
- 玲珑杯 1124
- Pyhton面向对象编程,修饰等
- 使用Adaboost训练手掌检测器
- C语言中字节对齐问题
- 计算机网络复习要点
- ORACLE 中in与exists语句的区别(一)
- 玲珑杯 1160
- squid代理及加速(理论加案例篇)
- 雨巷
- KMP 算法(1):如何理解 KMP 讲得特别好
- Python在pycharm中的调试(debug)
- JS中const,var,let区别
- 使用ORM、反射、泛型书写通用的增删改查方法
- css ico box-sizing 单行不换行省略
- jquery获取select标签选中的值