题目链接:点击查看

题目大意:给出一个集合 SSS,集合中的数是 [0,m)[0,m)[0,m) 且互不相同的,问从集合中选 nnn 次数字,且乘积对 mmm 取模后等于 xxx 的方案数有多少

题目分析:

考虑转移方程,我们设 f[i][j]f[i][j]f[i][j] 为选了 iii 个数后,乘积对 mmm 取余后为 jjj 的方案数,那么自然有 f[i+1][j]=∑ab≡j(modm)f[i][a]∗f[i][b]f[i+1][j]=\sum\limits_{ab\equiv j \pmod m}f[i][a]*f[i][b]f[i+1][j]=ab≡j(modm)∑​f[i][a]∗f[i][b]

需要注意到本题的 mmm 是一个特别小的质数,不难想到原根,设 ggg 为 mmm 的原根,可以得到一个性质就是 g1,g2,...,gm−1g^1,g^2,...,g^{m-1}g1,g2,...,gm−1 各不相同,且值域属于 [1,m)[1,m)[1,m)

所以将每个数换成其原根对应的数字后就可以化乘为加了,设 gA≡a(modm)g^A \equiv a \pmod mgA≡a(modm) 更具体的,原转移方程就可以书写为: f[i+1][j]=∑gAgB≡gJ(modm)f[i][A]∗f[i][B]f[i+1][j]=\sum\limits_{g^Ag^B\equiv g^J \pmod m}f[i][A]*f[i][B]f[i+1][j]=gAgB≡gJ(modm)∑​f[i][A]∗f[i][B] 因为 mmm 是质数,所以根据费马小定理降幂得到:f[i+1][j]=∑gA+B(modm−1)≡gJ(modm)f[i][A]∗f[i][B]f[i+1][j]=\sum\limits_{g^{A+B\pmod {m-1}}\equiv g^J \pmod m}f[i][A]*f[i][B]f[i+1][j]=gA+B(modm−1)≡gJ(modm)∑​f[i][A]∗f[i][B]

即 f[i+1][j]=∑A+B≡J(modm−1)f[i][A]∗f[i][B]f[i+1][j]=\sum\limits_{A+B\equiv J \pmod {m-1}}f[i][A]*f[i][B]f[i+1][j]=A+B≡J(modm−1)∑​f[i][A]∗f[i][B]

又因为每层的卷积的转移方程是相同的,可以用快速幂优化NTT,时间复杂度为 O(m∗logm∗logn)O(m*logm*logn)O(m∗logm∗logn)

有几个小细节需要注意:

  1. 因为模数从 mmm 变成了 m−1m-1m−1,原本 gm−1≡1(modm)g^{m-1}\equiv 1 \pmod mgm−1≡1(modm),这里的指数需要对 m−1m-1m−1 取模,换算到本题中应该变成 gm−1=g0=1g^{m-1}=g^{0}=1gm−1=g0=1,所以当原数为 111 时,对应的原根的指数应该为 000,几乎没有题解说明这个细节,自己想了好久才明白的
  2. SSS 集合中的 000 是没有贡献的,直接忽略即可
  3. 每次卷完之后,因为下标的取值是 [0,2∗(m−1))[0,2*(m-1))[0,2∗(m−1)) 的,所以需要将 [m−1,2∗(m−1))[m-1,2*(m-1))[m−1,2∗(m−1)) 这一部分的答案加到 [0,m−1)[0,m-1)[0,m−1) 上去

代码:

// Problem: P3321 [SDOI2015]序列统计
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3321
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f;
}
template<typename T>
inline void write(T x)
{if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
const int mod=1004535809,G=3,Gi=(mod+1)/3;
bool vis[8010];
int n,m,limit = 1,L,r[N],p[8010];
LL a[N],ans[N];
inline LL fastpow(LL a, LL k) {LL base = 1;while(k) {if(k & 1) base = (base * a ) % mod;a = (a * a) % mod;k >>= 1;}return base % mod;
}
inline void NTT(LL *A, int type) {for(int i = 0; i < limit; i++) if(i < r[i]) swap(A[i], A[r[i]]);for(int mid = 1; mid < limit; mid <<= 1) {    LL Wn = fastpow( type == 1 ? G : Gi , (mod - 1) / (mid << 1));for(int j = 0; j < limit; j += (mid << 1)) {LL w = 1;for(int k = 0; k < mid; k++, w = (w * Wn) % mod) {int x = A[j + k], y = w * A[j + k + mid] % mod;A[j + k] = (x + y) % mod,A[j + k + mid] = (x - y + mod) % mod;}}}if(type==-1) {LL inv=fastpow(limit,mod-2);for(int i=0;i<limit;i++) {A[i]=(A[i]*inv)%mod;}}
}
void q_pow(int n) {ans[0]=1;while(n) {NTT(a,1);if(n&1) {NTT(ans,1);for(int i=0;i<limit;i++) {ans[i]=ans[i]*a[i]%mod;}NTT(ans,-1);for(int i=limit-1;i>=m-1;i--) {ans[i-m+1]=(ans[i-m+1]+ans[i])%mod;ans[i]=0;}}for(int i=0;i<limit;i++) {a[i]=a[i]*a[i]%mod;}NTT(a,-1);for(int i=limit-1;i>=m-1;i--) {a[i-m+1]=(a[i-m+1]+a[i])%mod;a[i]=0;}n>>=1;}
}
int find_root(int mod)
{for(int i=2;i<mod;i++){memset(vis,false,sizeof(vis));bool flag=true;int x=i;for(int j=1;j<=mod-1;j++){if(vis[x]){flag=false;break;}vis[x]=true;x=x*i%mod;}if(flag)return i;}return -1;
}
int main()
{#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int x,S;read(n),read(m),read(x),read(S);while(limit<=m+m) limit<<=1,L++;for(int i=0;i<limit;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));int rt=find_root(m);int sum=1;for(int i=1;i<m-1;i++) {sum=sum*rt%m;p[sum]=i;}for(int i=0,x;i<S;i++) {read(x);if(x) {a[p[x]]=1;}}q_pow(n);cout<<ans[p[x]]<<endl;return 0;
}

洛谷 - P3321 [SDOI2015]序列统计(原根+NTT)相关推荐

  1. 洛谷3321 SDOI2015 序列统计

    懒得放传送[大雾 有趣的一道题 前几天刚好听到Creed_神犇讲到相乘转原根变成卷积的形式 看到这道题当然就会做了啊w 对于m很小 我们暴力找原根 如果你不会找原根的话 出门左转百度qwq 找到原根以 ...

  2. P3321 [SDOI2015]序列统计(离散对数下NTT,乘法换加法)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://www.luogu.com.cn/problem/P3321 Prob ...

  3. P3321 [SDOI2015]序列统计(未解决)

    P3321 [SDOI2015]序列统计 题意: 题解: 参考题解: 题解 P3321 [[SDOI2015]序列统计] [LG3321][SDOI2015]序列统计 神仙题..学透再补 代码:

  4. Luogu P3321 [SDOI2015]序列统计

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

  5. P3321 [SDOI2015]序列统计

    思路 首先有个挺显然的DP \[ dp[i][(j*k)\%m]+=dp[i-1][j]\times dp[i-1][k] \] 想办法优化这个DP 这个dp也可以写成这样 \[ dp[i][j]=\ ...

  6. [SDOI2015]序列统计 (NTT)

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

  7. 算法学习FFT系列(2):快速数论变换NTT bzoj3992: [SDOI2015]序列统计例题详解

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

  8. BZOJ3992[SDOI2015]序列统计

    题目链接 洛谷 BZOJ 解析 头一回知道原根还可以这么考-- 不难想到递推的做法\(dp[i][j]\)表示长度为\(i\),乘积为\(j\)的答案,那么\(dp[i][j \cdot a[i] \ ...

  9. [SDOI2015]序列统计

    [SDOI2015]序列统计 很有趣的一道题目,很巧妙. 显然是一个dp,考虑最朴素的dp,f[i][j]表示选i个乘起来,%m为j的方案数为多少.转移也很简单. 然而乘法的转移并不能进行什么优化,于 ...

最新文章

  1. 北语计算机应用基础2,北语17春《计算机应用基础》练习2
  2. java resultset jdbc_【JDBC系列】JDBC原生处理ResultSet
  3. 2017-2018-1 20155209 实验三 实时系统
  4. java ajax翻页_分页 工具类 前后台代码 Java JavaScript (ajax) 实现 讲解
  5. ubuntu下制作u盘镜像_deepin下制作win10启动U盘
  6. php oci8 11,Linux下PHP5.2 Oracle客户端扩展(OCI8)安装
  7. 详细介绍Linux shell脚本基础学习(一)
  8. 【火炉炼AI】深度学习008-Keras解决多分类问题
  9. 2014新浪研发project师实习笔试(哈尔滨站)
  10. hdu3947 给一些已知(需费用)路径去覆盖一些边 //预先加灌法费用流
  11. E20180418-hm
  12. 基于java开发的网上商城系统
  13. 基于ERDAS软件的高分三号(GF-3)SAR影像的预处理
  14. 2019-6-5-WPF-拼音输入法
  15. oracle插入获取当前时间,Oracle中如何获取系统当前时间
  16. 计算机毕业设计、课程设计之[含论文+源码等]S2SH+mysql的报刊订阅系统[包运行成功]
  17. 转一篇帖子-我是如何在网上卖鱼的
  18. pytorch里面nn.Module讲解
  19. JAVA 垃圾回收
  20. 如何用真实图案填充图片?

热门文章

  1. pytorch:Logistic回归
  2. sun java ide,1.6 JAVA IDE安装
  3. 字节流读数据(一次读一个字节数据)
  4. Java 扫描并加载包路径下class文件
  5. flume案例-网络数据采集-Flume的配置
  6. 数据库-优化-MYSQL数据库设计原则
  7. php 数组插入键和值,php数组中键和值的关系
  8. java课后习题_【整理】java私塾教程课后习题
  9. 直流无刷电机制动的三种方式
  10. Linux下main函数带参数问题和atoi函数详解