【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂
【BZOJ3992】[SDOI2015]序列统计
Description
Input
一行,四个整数,N、M、x、|S|,其中|S|为集合S中元素个数。第二行,|S|个整数,表示集合S中的所有元素。
Output
一行,一个整数,表示你求出的种类数mod 1004535809的值。
Sample Input
1 2
Sample Output
HINT
题解:如果你早已深入理解生成函数,可以无视下面这段话:
“未学生成函数的时候,以为这种题就是将两个桶相乘,得到一个新的桶,桶里装的是方案数。了解生成函数后,发现就是讲桶中的每一位都看成多项式中的一个系数,然后用多项式的运算法则来优化运算的过程,最后的答案依旧是其中的一位系数。如果像我一样对生成函数了解较少的话,可以先考虑DP,用DP方程将式子列出来,然后将整个DP数组看成一个大多项式,继续推下去就好。”
如果你早已深入理解NTT,可以无视下面这段话:
“NTT与FFT的区别是:FFT利用的是e的特性,将系数表达式与点值表达式进行快速的转换,而在NTT中,模数的原根正好有同样的性质,并且常见的就是998244353的一个原根=3。于是,只需要将单位复数根变成3的幂次,除法改成逆元,其余都一样了。”
如果你早已理解原根与指标,可以无视下面这段话:
“如果x^0,x^1,...x^n-1在mod n意义下正好覆盖了0-n-1中的所有数,则x是n的一个原根,他的意义可以看成是模意义下的e。而指标的意义,可以看成是模意义下的取ln。这两个东西在本题中的意义就是将乘法转变成加法。
“原根的求法:暴力枚举x,如果x对于$\varphi(p)$的所有质因子pi,都有$x^{\varphi(p) \over pi} \neq 1$,则x是p的原根。
“指标的求法:如果原根是r,则r^x的指标即为x。"
回到本题,我们将原数组求指标后,将得到的多项式^n即可,可以用多项式的快速幂实现。
- #include <cstdio>
- #include <cstring>
- #include <iostream>
- using namespace std;
- typedef long long ll;
- const ll P=1004535809ll;
- const ll G=3;
- const int maxn=100010;
- int n,m,X,S,root,num,len;
- ll pri[maxn],A[maxn],B[maxn];
- ll s[maxn],ind[maxn];
- inline int rd()
- {
- int ret=0,f=1; char gc=getchar();
- while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
- while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
- return ret*f;
- }
- ll pm(ll x,ll y,ll z)
- {
- ll ret=1;
- while(y)
- {
- if(y&1) ret=ret*x%z;
- x=x*x%z,y>>=1;
- }
- return ret;
- }
- void get_factor(ll x)
- {
- for(ll i=2;i*i<=x;i++)
- {
- if(x%i==0)
- {
- pri[++num]=i;
- while(x%i==0) x/=i;
- }
- }
- if(x!=1) pri[++num]=x;
- }
- bool check(ll x)
- {
- for(int i=1;i<=num;i++) if(pm(x,(m-1)/pri[i],m)==1) return 0;
- return 1;
- }
- ll get_root(ll x)
- {
- ll tmp=x-1;
- get_factor(tmp);
- for(ll i=2;i<=tmp;i++) if(check(i)) return i;
- return 0;
- }
- void NTT(ll *a,int f)
- {
- int i,j,k,h;
- ll t;
- for(i=k=0;i<len;i++)
- {
- if(i>k) swap(a[i],a[k]);
- for(j=len>>1;(k^=j)<j;j>>=1);
- }
- for(h=2;h<=len;h<<=1)
- {
- ll wn=pm(G,f==1?(P-1)/h:P-1-(P-1)/h,P);
- for(j=0;j<len;j+=h)
- {
- ll w=1;
- for(k=j;k<j+h/2;k++) t=w*a[k+h/2]%P,a[k+h/2]=(a[k]-t+P)%P,a[k]=(a[k]+t)%P,w=w*wn%P;
- }
- }
- if(f==-1)
- {
- t=pm(len,P-2,P);
- for(i=0;i<len;i++) a[i]=a[i]*t%P;
- }
- }
- void POW(ll *b,ll y)
- {
- ll *a=B;
- a[0]=1;
- while(y)
- {
- NTT(b,1);
- if(y&1)
- {
- NTT(a,1);
- for(int i=0;i<len;i++) a[i]=a[i]*b[i]%P;
- NTT(a,-1);
- for(int i=len-1;i>=m-1;i--) a[i-m+1]=(a[i-m+1]+a[i])%P,a[i]=0;
- }
- for(int i=0;i<len;i++) b[i]=b[i]*b[i]%P;
- NTT(b,-1);
- for(int i=len-1;i>=m-1;i--) b[i-m+1]=(b[i-m+1]+b[i])%P,b[i]=0;
- y>>=1;
- }
- }
- int main()
- {
- n=rd(),m=rd(),X=rd(),S=rd();
- int i;
- for(i=1;i<=S;i++) s[i]=rd();
- root=get_root(m);
- ll tmp=1;
- for(i=0;i<m-1;i++) ind[tmp]=i,tmp=tmp*root%m;
- for(len=1;len<=m+m;len<<=1);
- for(i=1;i<=S;i++) if(s[i]) A[ind[s[i]]]=1;
- POW(A,n);
- printf("%lld\n",B[ind[X]]);
- return 0;
- }
【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂的更多相关文章
- bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 (学习NTT:https://riteme.github.io/blog/2016-8 ...
- BZOJ3992: [SDOI2015]序列统计(NTT 原根 生成函数)
题意 题目链接 给出大小为\(S\)的集合,从中选出\(N\)个数,满足他们的乘积\(\% M = X\)的方案数 Sol 神仙题Orz 首先不难列出最裸的dp方程,设\(f[i][j]\)表示选了\ ...
- LOJ 2183 / SDOI2015 序列统计 (DP+矩阵快速幂)
题面 传送门 分析 考虑容斥原理,用总的方案数-不含质数的方案数 设\(dp1[i][j]\)表示前i个数,和取模p为j的方案数, \(dp2[i][j]\)表示前i个数,和取模p为j的方案数,且所有 ...
- 【BZOJ3992】【SDOI2015】序列统计 EGF+多项式快速幂+循环卷积
如果是求$n$个数之和在模$m$意义下为$x$,那么做法是显然的. 但是这道题问的是$n$个数之积在模m意义下为$x$,那么做法就和上面的问题不同. 考虑如何把乘法转换成加法(求log): 题目中有一 ...
- BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1155 Solved: 532[Submit][Statu ...
- [BZOJ3992][SDOI2015]序列统计(DP+原根+NTT)
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1888 Solved: 898[Submit][Statu ...
- 【NTT】bzoj3992: [SDOI2015]序列统计
板子题都差点不会了 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数 列,数列中的每个数都属于集合S.小C用这个生成器生 ...
- [SDOI2015]序列统计(NTT+求原根)
题目 [SDOI2015]序列统计 挺好的题!!! 做法 \(f[i][j]\)为第\(i\)个数前缀积在模\(M\)意义下为\(j\) 显然是可以快速幂的:\[f[2*i][j]=\sum\limi ...
- BZOJ3992: [SDOI2015]序列统计
Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列. ...
随机推荐
- LeetCode OJ-- Longest Common Prefix
https://oj.leetcode.com/problems/longest-common-prefix/ 在多个string的集合中,找出所有string的最长公共前缀. 从头开始 index ...
- PHP中的stristr(),strstr(),strpos()速度比较
测速代码: <?php function getmicrotime() { list($usec, $sec) = explode(" ",microtime()); ret ...
- Codeforces 546D Soldier and Number Game(数论)
类似筛素数的方法……求出前缀和.然后直接O(1)回答即可. #include <bits/stdc++.h> using namespace std; #define rep(i,a,b) ...
- github如何实现fork的项目与原项目同步
refer to https://www.jianshu.com/p/fede3333205f 作者:hitchc 链接:https://www.jianshu.com/p/fede3333205f ...
- GestureDetector 完全解析
个人原创 OnDown(MotionEvent e):用户触发DonenEvent就会执行onShowPress(MotionEvent e):用户触发DonenEvent后,在很短大概0.5秒内,没 ...
- CSS 属性选择器的深入挖掘
CSS 属性选择器,可以通过已经存在的属性名或属性值匹配元素. 属性选择器是在 CSS2 中引入的并且在 CSS3 中得到了很好拓展.本文将会比较全面的介绍属性选择器,尽可能的去挖掘这个选择器在不同场 ...
- 简单便捷的纯PHP网盘程序 Veno File Manager 2.6.3(VFM2)
体验过很多国外网盘程序,例如:Owncloud.Bedrive.YetiShare.XFilesharing.uCloud.Cloudshare 等等,诸如此类,VFM2与这些臃肿的商用或非商用来的程 ...
- 优化算法——拟牛顿法之L-BFGS算法
一.BFGS算法 在"优化算法--拟牛顿法之BFGS算法"中,我们得到了BFGS算法的校正公式: 利用Sherman-Morrison公式可对上式进行变换,得到 令,则得到: 二. ...
- ES聚合查询实例
查询特定渠道分享数量最大的30个文章的uuid: { , "query": { "bool": { "must": [ { "te ...
- browsersync按照官网,然后本地配置后,动态监听时不起作用
官方API也未曾标注,要添加文件指向 --files 所以解决方案就是: browser-sync start --proxy "tp5.cn" --files "css ...