[SDOI2015]序列统计
[SDOI2015]序列统计
很有趣的一道题目,很巧妙。
显然是一个dp,考虑最朴素的dp,f[i][j]表示选i个乘起来,%m为j的方案数为多少。转移也很简单。
然而乘法的转移并不能进行什么优化,于是考虑设法将其转为加法。
我们可以通过求出m的原根,因为原根G,G^i %m(1<=i<m)是一一对应1<=x<m的所以我们将原本S集合中的元素由"x"替换为"i",这样就完成了由乘法向加法的转换,但是需要注意的是,此时的模数并不再是m而是m-1,。下文中的m均为输入的m-1后的值。
那么问题就转换为了从一堆数中选n个加起来,最终%m为j的方案数为多少,如果我们用g数组来表示某一个元素是否存在,我们发现f[i+1][j]是由f[i][k]*g[(j-k+m)%m](0<=k<m)转移而来,我们发现他很像卷积的形式,但是%m怎么处理呢?
这里get了一个新技能,好像叫循环卷积。
就是计算f和g的卷积后,对于m<=i<l这一段,将他的值加到i%m上去。
f数组自然是可以重复使用的。
那么我们重复卷积n次,得到的即为最终答案。
然而n太大了。
卷积是具有交换律和结合律的,所以可以用快速幂来加速这一过程。
整体复杂度mlogmlogn
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int inf=4e4+10; 4 const int mod=1004535809; 5 int n,m,x,s; 6 int a[inf]; 7 int fast(int x,int y,int z){ 8 int ans=1; 9 while(y){ 10 if(y&1)ans=1ll*ans*x%z; 11 x=1ll*x*x%z; 12 y>>=1; 13 } 14 return ans; 15 } 16 namespace RT{ 17 int tmp[inf],cnt; 18 bool check(int x,int y){ 19 for(int i=1;i<=cnt;i++){ 20 if(::fast(x,(y-1)/tmp[i],y)==1)return 0; 21 } 22 return 1; 23 } 24 int get_rt(int x){ 25 int u=x; 26 x--; 27 for(int i=2;i*i<=x;i++){ 28 if(x%i)continue; 29 tmp[++cnt]=i; 30 while(x%i==0)x/=i; 31 } 32 if(x>1)tmp[++cnt]=x; 33 int now=2; 34 while(1){ 35 if(check(now,u))return now; 36 now++; 37 } 38 } 39 } 40 int hs[inf]; 41 int g[inf],f[inf]; 42 int r[inf]; 43 void ntt(int *a,int l,int type){ 44 for(int i=0;i<l;i++) 45 if(i<r[i])swap(a[i],a[r[i]]); 46 for(int i=2;i<=l;i<<=1){ 47 int wn=fast(3,(type*(mod-1)/i+(mod-1))%(mod-1),mod); 48 for(int j=0;j<l;j+=i){ 49 int w=1; 50 for(int k=j;k<j+i/2;k++,w=1ll*w*wn%mod){ 51 int u=a[k],v=1ll*w*a[k+i/2]%mod; 52 a[k]=(u+v)%mod; 53 a[k+i/2]=(u-v+mod)%mod; 54 } 55 } 56 } 57 } 58 int main() 59 { 60 freopen("sdoi2015_sequence.in","r",stdin); 61 freopen("sdoi2015_sequence.out","w",stdout); 62 scanf("%d%d%d%d",&n,&m,&x,&s); 63 for(int i=1;i<=s;i++)scanf("%d",&a[i]); 64 int G=RT::get_rt(m); 65 for(int i=1;i<m;i++)hs[fast(G,i,m)]=i; 66 m--; 67 for(int i=1;i<=s;i++) 68 if(a[i])g[hs[a[i]]%m]=1; 69 int l=1,h=0; 70 while(l<m*2-1)l<<=1,h++; 71 for(int i=0;i<l;i++) 72 r[i]=(r[i>>1]>>1)+((i&1)<<(h-1)); 73 int inv=fast(l,mod-2,mod); 74 f[0]=1; 75 while(n){ 76 ntt(g,l,1); 77 if(n&1){ 78 ntt(f,l,1); 79 for(int i=0;i<l;i++)f[i]=1ll*f[i]*g[i]%mod; 80 ntt(f,l,-1); 81 for(int i=0;i<l;i++)f[i]=1ll*f[i]*inv%mod; 82 for(int i=m;i<l;i++)f[i%m]=(f[i%m]+f[i])%mod,f[i]=0; 83 } 84 for(int i=0;i<l;i++)g[i]=1ll*g[i]*g[i]%mod; 85 ntt(g,l,-1); 86 for(int i=0;i<l;i++)g[i]=1ll*g[i]*inv%mod; 87 for(int i=m;i<l;i++)g[i%m]=(g[i%m]+g[i])%mod,g[i]=0; 88 n>>=1; 89 } 90 printf("%d\n",f[hs[x]%m]); 91 return 0; 92 }
View Code
转载于:https://www.cnblogs.com/hyghb/p/8519413.html
[SDOI2015]序列统计相关推荐
- P3321 [SDOI2015]序列统计(离散对数下NTT,乘法换加法)
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://www.luogu.com.cn/problem/P3321 Prob ...
- Luogu P3321 [SDOI2015]序列统计
[SDOI2015]序列统计 题目描述 小C有一个集合\(S\),里面的元素都是小于\(M\)的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为\(N\)的数列,数列中的每个数都属于集合\( ...
- 洛谷 - P3321 [SDOI2015]序列统计(原根+NTT)
题目链接:点击查看 题目大意:给出一个集合 SSS,集合中的数是 [0,m)[0,m)[0,m) 且互不相同的,问从集合中选 nnn 次数字,且乘积对 mmm 取模后等于 xxx 的方案数有多少 题目 ...
- P3321 [SDOI2015]序列统计(未解决)
P3321 [SDOI2015]序列统计 题意: 题解: 参考题解: 题解 P3321 [[SDOI2015]序列统计] [LG3321][SDOI2015]序列统计 神仙题..学透再补 代码:
- 算法学习FFT系列(2):快速数论变换NTT bzoj3992: [SDOI2015]序列统计例题详解
bzoj3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属 ...
- BZOJ3992[SDOI2015]序列统计
题目链接 洛谷 BZOJ 解析 头一回知道原根还可以这么考-- 不难想到递推的做法\(dp[i][j]\)表示长度为\(i\),乘积为\(j\)的答案,那么\(dp[i][j \cdot a[i] \ ...
- P3321 [SDOI2015]序列统计
思路 首先有个挺显然的DP \[ dp[i][(j*k)\%m]+=dp[i-1][j]\times dp[i-1][k] \] 想办法优化这个DP 这个dp也可以写成这样 \[ dp[i][j]=\ ...
- BZOJ3992:[SDOI2015]序列统计——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3992 https://www.luogu.org/problemnew/show/P3321 小C ...
- BZOJ 3992 [SDOI2015]序列统计
数列长度到了109,转移矩阵边长n到了8000,除了FFT还能怎么写??!! 当然,这题由于取模,必须用NTT. 同时由于取得是乘积,所以用m的原根来搞,每次NTT完了,把后面的部分加到前面去. 注意 ...
最新文章
- python数据分析实训大纲,数据分析大赛考纲:(二)Python数据分析应会部分
- 机器学习(18)-- SVM支持向量机(根据身高体重分类性别)
- oracle aced什么资质,ACOUG 中国行—暨Oracle WDP云数据之旅,火热报名中……
- containers文件夹可以删除吗_电脑进行C盘清理,appdata文件夹可以删除吗?
- 宝塔面板 windows 2012 mysql 允许远程连接
- LeetCode 1945. 字符串转化后的各位数字之和
- python机器学习案例系列教程——聚类算法总结
- ios 进入后台 一段时间在进入前台 动画消失
- 社交网络影响力最大化
- Android 分贝测试仪功能,华为移动终端开发
- 广义线性模型之泊松回归
- 高通平台文档下载【学习笔记】
- 未来几年,自动化发展趋势展望
- oracle数据库用户状态失效Expired
- win7系统盘瘦身秘诀
- Oracle创建数据库连接——DATABASE LINKS
- 【Mysql】Mysql GTID复制进程出现异常,出现断点
- css解决图片缩小变模糊问题
- 使用ip小魔棒让外部网络访问内网中的资源
- ionic3 版本更新
热门文章
- jdbc连接oracle数据库
- java ajax级联_jQuery ajax级联二级菜单(转)
- Opencv---remap函数的实现
- 误删/var/lib/dpkg/info,文件解决方案(是否完全解决,不确定)
- java timetasker_Java网络与多线程系列之1:实现一个简单的对象池
- Virtual Treeview 5 0 0的安装以及入门
- 推荐系统知识梳理——矩阵分解
- Java7并发编程指南——第七章:定制并发类
- notepad自动对齐html代码,notepad如何存储为html格式化
- 风控策略和模型的区别_风控策略概述