3992: [SDOI2015]序列统计

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 2275  Solved: 1090
[Submit][Status][Discuss]

Description

小C有一个集合S,里面的元素都是小于M的非负整数。他用程序编写了一个数列生成器,可以生成一个长度为N的数
列,数列中的每个数都属于集合S。小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:
给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个。小C认为
,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi。另外,小C认为这个问题的答案可能很大
,因此他只需要你帮助他求出答案mod 1004535809的值就可以了。

Input

一行,四个整数,N、M、x、|S|,其中|S|为集合S中元素个数。
第二行,|S|个整数,表示集合S中的所有元素。
1<=N<=10^9,3<=M<=8000,M为质数
0<=x<=M-1,输入数据保证集合S中元素不重复x∈[1,m-1]

集合中的数∈[0,m-1]

Output

一行,一个整数,表示你求出的种类数mod 1004535809的值。

Sample Input

4 3 1 2
1 2

Sample Output

8
【样例说明】
可以生成的满足要求的不同的数列有(1,1,1,1)、(1,1,2,2)、(1,2,1,2)、(1,2,2,1)、
(2,1,1,2)、(2,1,2,1)、(2,2,1,1)、(2,2,2,2)

题解

这题的要求非常类似背包, 但是值之间做的贡献是乘积的形式. 我们考虑把它转成加法.

怎么转加法呢? 当然是取对数了!

离散对数哪家强? SDOI找...(划掉)

注意到如果数列里有 $0$ 那么贡献就是 $0$, 但是题目规定要求的目标值非 $0$, 所以我们首先先把 $0$ 扔掉

然后暴力计算出 $m$ 的一个原根, 同时处理出每个数的对数

那么这就是一个长度为 $m-1$ 的循环卷积辣!

然而循环卷积需要膜数有 $m-1$ 次单位根(吧), 于是只能NTT倍增爆算了...(或者博主naive?)

参考代码

多项式左右移操作现已加入豪华午餐

  1. #include <bits/stdc++.h>
  2.  
  3. const int G=;
  4. const int DFT=;
  5. const int IDFT=-;
  6. const int MAXN=;
  7. const int MOD=;
  8. const int INV2=(MOD+)>>;
  9. const int PHI=MOD-;
  10.  
  11. typedef std::vector<int> Poly;
  12.  
  13. Poly Sqrt(Poly);
  14. void Read(Poly&);
  15. Poly Inverse(Poly);
  16. Poly Ln(const Poly&);
  17. Poly Exp(const Poly&);
  18. void Print(const Poly&);
  19. void NTT(Poly&,int,int);
  20. Poly Pow(const Poly&,int);
  21. Poly Integral(const Poly&);
  22. Poly Derivative(const Poly&);
  23. Poly operator*(Poly,Poly);
  24. Poly operator/(Poly,Poly);
  25. Poly operator%(Poly,Poly);
  26. Poly operator<<(const Poly&,int);
  27. Poly operator>>(const Poly&,int);
  28. Poly operator+(const Poly&,const Poly&);
  29. Poly operator-(const Poly&,const Poly&);
  30.  
  31. int rev[MAXN];
  32.  
  33. int FindG(int);
  34. int NTTPre(int);
  35. int Sqrt(int,int);
  36. int Pow(int,int,int);
  37. int Log(int,int,int);
  38. int ExGCD(int,int,int&,int&);
  39.  
  40. int k,m,x,n;
  41. int lg[MAXN];
  42.  
  43. int main(){
  44. scanf("%d%d%d%d",&k,&m,&x,&n);
  45. Poly a(m-);
  46. int g=FindG(m);
  47. for(int i=,pw=;i<m-;i++,pw=pw*g%m)
  48. lg[pw]=i;
  49. for(int i=;i<n;i++){
  50. int x;
  51. scanf("%d",&x);
  52. if(x)
  53. a[lg[x]]=;
  54. }
  55. --m;
  56. Poly ans(a);
  57. --k;
  58. while(k>){
  59. if(k&){
  60. ans=a*ans;
  61. ans=ans+(ans>>m);
  62. ans.resize(m);
  63. }
  64. a=a*a;
  65. a=a+(a>>m);
  66. a.resize(m);
  67. k>>=;
  68. }
  69. printf("%d\n",ans[lg[x]]);
  70. return ;
  71. }
  72.  
  73. Poly operator<<(const Poly& a,int x){
  74. Poly ans(a.size()+x);
  75. for(size_t i=;i<a.size();i++)
  76. ans[i+x]=a[i];
  77. return ans;
  78. }
  79.  
  80. Poly operator>>(const Poly& a,int x){
  81. Poly ans(a.size()-x);
  82. for(size_t i=x;i<a.size();i++)
  83. ans[i-x]=a[i];
  84. return ans;
  85. }
  86.  
  87. int FindG(int mod){
  88. for(int g=;g<mod;g++){
  89. bool flag=true;
  90. for(int i=,pw=g;i<mod-;i++,pw=pw*g%mod){
  91. if(pw==){
  92. flag=false;
  93. break;
  94. }
  95. }
  96. if(flag)
  97. return g;
  98. }
  99. return -;
  100. }
  101.  
  102. void Read(Poly& a){
  103. for(auto& i:a)
  104. scanf("%d",&i);
  105. }
  106.  
  107. void Print(const Poly& a){
  108. for(auto i:a)
  109. printf("%d ",i);
  110. puts("");
  111. }
  112.  
  113. Poly Pow(const Poly& a,int k){
  114. Poly log=Ln(a);
  115. for(auto& i:log)
  116. i=1ll*i*k%MOD;
  117. return Exp(log);
  118. }
  119.  
  120. Poly Sqrt(Poly a){
  121. int len=a.size();
  122. if(len==)
  123. return Poly(,Sqrt(a[],MOD));
  124. else{
  125. Poly b=a;
  126. b.resize((len+)>>);
  127. b=Sqrt(b);
  128. b.resize(len);
  129. Poly inv=Inverse(b);
  130. int bln=NTTPre(inv.size()+a.size());
  131. NTT(a,bln,DFT);
  132. NTT(inv,bln,DFT);
  133. for(int i=;i<bln;i++)
  134. a[i]=1ll*a[i]*INV2%MOD*inv[i]%MOD;
  135. NTT(a,bln,IDFT);
  136. for(int i=;i<len;i++)
  137. b[i]=(1ll*b[i]*INV2%MOD+a[i])%MOD;
  138. return b;
  139. }
  140. }
  141.  
  142. Poly Exp(const Poly& a){
  143. size_t len=;
  144. Poly ans(,),one(,);
  145. while(len<(a.size()<<)){
  146. len<<=;
  147. Poly b=a;
  148. b.resize(len);
  149. ans=ans*(one-Ln(ans)+b);
  150. ans.resize(len);
  151. }
  152. ans.resize(a.size());
  153. return ans;
  154. }
  155.  
  156. Poly Ln(const Poly& a){
  157. Poly ans=Integral(Derivative(a)*Inverse(a));
  158. ans.resize(a.size());
  159. return ans;
  160. }
  161.  
  162. Poly Integral(const Poly& a){
  163. int len=a.size();
  164. Poly ans(len+);
  165. for(int i=;i<len;i++)
  166. ans[i]=1ll*a[i-]*Pow(i,MOD-,MOD)%MOD;
  167. return ans;
  168. }
  169.  
  170. Poly Derivative(const Poly& a){
  171. int len=a.size();
  172. Poly ans(len-);
  173. for(int i=;i<len;i++)
  174. ans[i-]=1ll*a[i]*i%MOD;
  175. return ans;
  176. }
  177.  
  178. Poly operator/(Poly a,Poly b){
  179. int n=a.size()-,m=b.size()-;
  180. Poly ans();
  181. if(n>=m){
  182. std::reverse(a.begin(),a.end());
  183. std::reverse(b.begin(),b.end());
  184. b.resize(n-m+);
  185. ans=Inverse(b)*a;
  186. ans.resize(n-m+);
  187. std::reverse(ans.begin(),ans.end());
  188. }
  189. return ans;
  190. }
  191.  
  192. Poly operator%(Poly a,Poly b){
  193. int n=a.size()-,m=b.size()-;
  194. Poly ans;
  195. if(n<m)
  196. ans=a;
  197. else
  198. ans=a-(a/b)*b;
  199. ans.resize(m);
  200. return ans;
  201. }
  202.  
  203. Poly operator*(Poly a,Poly b){
  204. int len=a.size()+b.size()-;
  205. int bln=NTTPre(len);
  206. NTT(a,bln,DFT);
  207. NTT(b,bln,DFT);
  208. for(int i=;i<bln;i++)
  209. a[i]=1ll*a[i]*b[i]%MOD;
  210. NTT(a,bln,IDFT);
  211. a.resize(len);
  212. return a;
  213. }
  214.  
  215. Poly operator+(const Poly& a,const Poly& b){
  216. Poly ans(std::max(a.size(),b.size()));
  217. std::copy(a.begin(),a.end(),ans.begin());
  218. for(size_t i=;i<b.size();i++)
  219. ans[i]=(ans[i]+b[i])%MOD;
  220. return ans;
  221. }
  222.  
  223. Poly operator-(const Poly& a,const Poly& b){
  224. Poly ans(std::max(a.size(),b.size()));
  225. std::copy(a.begin(),a.end(),ans.begin());
  226. for(size_t i=;i<b.size();i++)
  227. ans[i]=(ans[i]+MOD-b[i])%MOD;
  228. return ans;
  229. }
  230.  
  231. Poly Inverse(Poly a){
  232. int len=a.size();
  233. if(len==)
  234. return Poly(,Pow(a[],MOD-,MOD));
  235. else{
  236. Poly b(a);
  237. b.resize((len+)>>);
  238. b=Inverse(b);
  239. int bln=NTTPre(b.size()*+a.size());
  240. NTT(a,bln,DFT);
  241. NTT(b,bln,DFT);
  242. for(int i=;i<bln;i++)
  243. b[i]=(2ll*b[i]%MOD-1ll*b[i]*b[i]%MOD*a[i]%MOD+MOD)%MOD;
  244. NTT(b,bln,IDFT);
  245. b.resize(len);
  246. return b;
  247. }
  248. }
  249.  
  250. void NTT(Poly& a,int len,int opt){
  251. a.resize(len);
  252. for(int i=;i<len;i++)
  253. if(rev[i]>i)
  254. std::swap(a[i],a[rev[i]]);
  255. for(int i=;i<len;i<<=){
  256. int step=i<<;
  257. int wn=Pow(G,(PHI+opt*PHI/step)%PHI,MOD);
  258. for(int j=;j<len;j+=step){
  259. int w=;
  260. for(int k=;k<i;k++,w=1ll*w*wn%MOD){
  261. int x=a[j+k];
  262. int y=1ll*a[j+k+i]*w%MOD;
  263. a[j+k]=(x+y)%MOD;
  264. a[j+k+i]=(x-y+MOD)%MOD;
  265. }
  266. }
  267. }
  268. if(opt==IDFT){
  269. int inv=Pow(len,MOD-,MOD);
  270. for(int i=;i<len;i++)
  271. a[i]=1ll*a[i]*inv%MOD;
  272. }
  273. }
  274.  
  275. int NTTPre(int n){
  276. int bln=,bct=;
  277. while(bln<n){
  278. bln<<=;
  279. ++bct;
  280. }
  281. for(int i=;i<bln;i++)
  282. rev[i]=(rev[i>>]>>)|((i&)<<(bct-));
  283. return bln;
  284. }
  285.  
  286. inline int Pow(int a,int n,int p){
  287. int ans=;
  288. while(n>){
  289. if(n&)
  290. ans=1ll*a*ans%p;
  291. a=1ll*a*a%p;
  292. n>>=;
  293. }
  294. return ans;
  295. }
  296.  
  297. int ExGCD(int a,int b,int& x,int& y){
  298. if(b==){
  299. x=,y=;
  300. return a;
  301. }
  302. else{
  303. int gcd=ExGCD(b,a%b,y,x);
  304. y-=x*(a/b);
  305. return gcd;
  306. }
  307. }
  308.  
  309. inline int Sqrt(int a,int p){
  310. int s=Pow(G,Log(G,a,p)>>,p);
  311. return std::min(s,MOD-s);
  312. }
  313.  
  314. inline int Log(int a,int x,int p){
  315. int s=sqrt(p+0.5);
  316. int inv=Pow(Pow(a,s,p),p-,p);
  317. std::unordered_map<int,int> m;
  318. m[]=;
  319. int pow=;
  320. for(int i=;i<s;i++){
  321. pow=1ll*a*pow%p;
  322. if(!m.count(pow))
  323. m[pow]=i;
  324. }
  325. for(int i=;i<s;i++){
  326. if(m.count(x))
  327. return i*s+m[x];
  328. x=1ll*x*inv%MOD;
  329. }
  330. return -;
  331. }

BZOJ 3992

[BZOJ 3992][SDOI2015]序列统计的更多相关文章

  1. BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1017  Solved: 466[Submit][Statu ...

  2. BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1155  Solved: 532[Submit][Statu ...

  3. BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)

    3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S ...

  4. bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 有转移次数.模M余数.方案数三个值,一看就是系数的地方放一个值.指数的地方放一个值.做 ...

  5. bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 (学习NTT:https://riteme.github.io/blog/2016-8 ...

  6. BZOJ.3992.[SDOI2015]序列统计(DP NTT 原根)

    题目链接 \(Description\) 给定\(n,m,x\)和集合\(S\).求\(\prod_{i=1}^na_i\equiv x\ (mod\ m)\)的方案数.其中\(a_i\in S\). ...

  7. bzoj 3992: [SDOI2015]序列统计【原根+生成函数+NTT+快速幂】

    还是没有理解透原根--题目提示其实挺明显的,M是质数,然后1<=x<=M-1 这种计数就容易想到生成函数,但是生成函数是加法,而这里是乘法,所以要想办法变成加法 首先因为0和任何数乘都是0 ...

  8. bzoj 3992: [SDOI2015]序列统计 NTT+原根

    今天开始学习丧心病狂的多项式qaq......    . code: #include <bits/stdc++.h> #define ll long long #define setIO ...

  9. 3992: [SDOI2015]序列统计

    3992: [SDOI2015]序列统计 链接 分析: 给定一个集和s,求多少个长度为n的序列,满足序列中每个数都属于s,并且所有数的乘积模m等于x. 设$f=\sum\limits_{i=0}^{n ...

随机推荐

  1. [转]MAC:删除终端默认前缀的计算机名

    MAC:删除终端默认前缀的计算机名 1.打开终端 输入 sudo vi /etc/bashrc,提示输入密码就是计算机的密码. 2.点击i将编辑模式改成insert修改文档,使用#注释PS1=’\h: ...

  2. SqlHelper---操作数据库

    public class SqlHelper { /// <summary> /// 数据库连接字符串 /// </summary> public static readonl ...

  3. JavaScript对象——原型与原型链

    原型与原型链 一. 普通对象与函数对象 JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object .Function 是 JS 自带的函数对象.下面举例说明 va ...

  4. 第5章 scrapy爬取知名问答网站

    第五章感觉是第四章的练习项目,无非就是多了一个模拟登录. 不分小节记录了,直接上知识点,可能比较乱. 1.常见的httpcode: 2.怎么找post参数? 先找到登录的页面,打开firebug,输入 ...

  5. 欢迎来到GIS思考者的博客www.gisthinker.com

    我是一名GIS爱好者,这是我的个人博客,欢迎点击: GIS思考者:www.gisthinker.com

  6. TRUNCATE TABLE 与 DELETE的区别

    delete from aatruncate table aa 区别1.delete from后面可以写条件,truncate不可以2.delete from记录是一条条删的,所删除的每行记录都会进日 ...

  7. Jquery Easy UI初步学习(一)

    Easy UI 1.3.2 以前听说Easy UI很不错,当了一个dome,闲着没事就看了一下,也整理一下为了自己更好的记忆,也希望对象我这样小菜有帮助吧 先从后台管理的主页面开始,如要要做主页需要了 ...

  8. 实例-PHP_SELF、 SCRIPT_NAME、 REQUEST_URI区别-获取前台公用文-dirname-PHP的"魔术常量"-str_replace

    Part1:实例 $_SERVER[PHP_SELF], $_SERVER[SCRIPT_NAME], $_SERVER['REQUEST_URI'] 在用法上是非常相似的,他们返回的都是与当前正在使 ...

  9. 前端(七):ES6一些新特性

    一.变量 1.var关键字的弊端 var关键字的弊端:1.可以重复声明变量:2.无法限制变量修改:3.没有块级作用域,只有函数作用域. <html lang="en"> ...

  10. 【SSH网上商城项目实战19】订单信息的级联入库以及页面的缓存问题

          转自: https://blog.csdn.net/eson_15/article/details/51433247 购物车这一块还剩最后两个问题,就是订单信息的级联入库和页面缓存,这里的 ...