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)

solution

设f[i][j]f[i][j]f[i][j]:表示选了iii个数的乘积%m=j\%m=j%m=j的方案数
f[i<<1][j]=∑(j1×j2)%m=jf[i][j1]×f[i][j2]f[i<<1][j]=\sum_{(j_1\times j_2)\%m=j}f[i][j_1]\times f[i][j_2]f[i<<1][j]=(j1​×j2​)%m=j∑​f[i][j1​]×f[i][j2​]
乘法目前来说是超越知识
那么将相乘转化为指数上的相加,暴艹出mmm的原根
题目保证了mmm是质数,一定会有原根
f[i<<1][j]=∑(j1+j2)%m=jf[i][j1]×f[i][j2]f[i<<1][j]=\sum_{(j_1+j_2)\%m=j}f[i][j_1]\times f[i][j_2]f[i<<1][j]=(j1​+j2​)%m=j∑​f[i][j1​]×f[i][j2​]
这就长得很像可以卷积的玩意儿
涉及取模那就用NTTNTTNTT
但是这个跟普通的式子下面的条件略有不同j1+j2=jj_1+j_2=jj1​+j2​=j
[m−1,2m−2][m-1,2m-2][m−1,2m−2]这里面也会对答案有贡献,被m−1m-1m−1取模

code

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
#define mod 1004535809
#define maxn 20000
int g, len = 1, inv;
int r[maxn], ans[maxn], f[maxn], fi[maxn];int qkpow( int x, int y, int MOD ) {int ans = 1;while( y ) {if( y & 1 ) ans = ans * x % MOD;x = x * x % MOD;y >>= 1;}return ans;
}void NTT( int *c, int f ) {for( int i = 0;i < len;i ++ )if( i < r[i] ) swap( c[i], c[r[i]] );for( int i = 1;i < len;i <<= 1 ) {int omega = qkpow( ( f == 1 ) ? 3 : mod / 3 + 1, ( mod - 1 ) / ( i << 1 ), mod );for( int j = 0;j < len;j += ( i << 1 ) ) {int w = 1;for( int k = 0;k < i;k ++, w = w * omega % mod ) {int x = c[j + k], y = w * c[j + k + i] % mod;c[j + k] = ( x + y ) % mod;c[j + k + i] = ( x - y + mod ) % mod;}}}if( f == -1 ) {for( int i = 0;i < len;i ++ )c[i] = c[i] * inv % mod;}
}void root( int m ) {int phi = m - 1;for( int i = 2;i < m;i ++ ) {bool flag = 1;int x = phi;for( int j = 2;j * j <= x;j ++ ) {if( phi % j ) continue;while( x % j == 0 ) x /= j;if( qkpow( i, phi / j, m ) == 1 ) {flag = 0;break;}}if( x > 1 && qkpow( i, phi / x, m ) == 1 ) continue;if( flag ) {g = i;return;} }
}signed main() {int n, m, x, s;scanf( "%lld %lld %lld %lld", &n, &m, &x, &s );root( m );for( int i = 0;i < m - 1;i ++ ) fi[qkpow( g, i, m )] = i;
//g^i=_(mod m) 相乘转化为指数相加 指数相加就可以用NTT暴艹卷积  for( int i = 1, a;i <= s;i ++ ) {scanf( "%lld", &a );if( ! a ) continue;else f[fi[a]] ++;}int l = 0;while( len <= ( ( m - 1 ) << 1 ) ) {len <<= 1;l ++;}inv = qkpow( len, mod - 2, mod );for( int i = 0;i < len;i ++ )r[i] = ( r[i >> 1] >> 1 ) | ( ( i & 1 ) << ( l - 1 ) );ans[0] = 1;while( n ) {if( n & 1 ) {NTT( f, 1 );NTT( ans, 1 );for( int i = 0;i < len;i ++ ) ans[i] = ans[i] * f[i] % mod;NTT( f, -1 );NTT( ans, -1 );for( int i = m - 1;i < len;i ++ )
//a^b=_(%p)<=>a^[b%phi(p)]=_(%p) 指数以m-1为一个循环节 在%m后应该都是一样的 对最后%m=x的答案可能会有贡献 ans[i % ( m - 1 )] = ( ans[i % ( m - 1 )] + ans[i] ) % mod, ans[i] = 0;}NTT( f, 1 );for( int i = 0;i < len;i ++ ) f[i] = f[i] * f[i] % mod;NTT( f, -1 );for( int i = m - 1;i < len;i ++ ) f[i % ( m - 1 )] = ( f[i % ( m - 1 )] + f[i] ) % mod, f[i] = 0;n >>= 1;}printf( "%lld\n", ans[fi[x]] );return 0;
}

[SDOI2015]序列统计 (NTT)相关推荐

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

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

  2. 洛谷 - P3321 [SDOI2015]序列统计(原根+NTT)

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

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

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

  4. Luogu P3321 [SDOI2015]序列统计

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

  5. [SDOI2015]序列统计

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

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

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

  7. BZOJ3992[SDOI2015]序列统计

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

  8. P3321 [SDOI2015]序列统计

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

  9. BZOJ 3992 [SDOI2015]序列统计

    数列长度到了109,转移矩阵边长n到了8000,除了FFT还能怎么写??!! 当然,这题由于取模,必须用NTT. 同时由于取得是乘积,所以用m的原根来搞,每次NTT完了,把后面的部分加到前面去. 注意 ...

最新文章

  1. mysqldiff对比主从表结构是否一致
  2. pythonjson数据提取_python爬虫学习笔记(十)-数据提取之JsonPath的使用
  3. sql server 2014 判断一个列某个字段是否相同_Select * from user的千层套路——一个sql是如何执行的...
  4. do not back up文件夹属性
  5. 从 0.99999... = 1 到芝诺悖论
  6. 【机器人学习】机器人轨迹规划A※算法代码
  7. seaweedfs问题处理
  8. TCP segment of a reassembled PDU,就这么简单!
  9. Maven知识补充(项目模型变量,Maven属性,依赖项的范围,查找公共存储库的依赖项等)
  10. Miracast协议
  11. Flutter技术与实战(4)
  12. 【Unity3D日常开发】Unity3D中实现屏幕坐标和3维空间坐标的转化
  13. 嵌入式技术学习总结二
  14. python3+pyqt5实现简易机票预订系统
  15. debian 安装wine
  16. Sketch教程|Sketch图层如何使用?如何使用Sketch画板?
  17. 计算机辅助手段在英语教学中使用,试谈计算机在英语教学中的辅助作用
  18. VBIDE.VBE的应用
  19. Linux开机报init错误,你好,Linux系统启动报kernelpanic- not syncing: attempted to kil init! 网上的办法我试了没有解决。...
  20. CCS6创建TMS320F2812工程

热门文章

  1. 从概念到案例:初学者须知的十大机器学习算法
  2. 《SAS编程与数据挖掘商业案例》学习笔记之九
  3. 四元数左乘右乘_四元数、欧拉角学习笔记个人理解
  4. 双目三维重建_【光电视界】简单介绍双目视觉三维重构
  5. c语言宏高级用法,C语言宏高级用法 [总结]
  6. 圆形比例分布图怎么做_解读宝山区2035总体规划:建设用地的比例在上海非中心城区中最高...
  7. python浅拷贝_Python中的浅拷贝和深拷贝
  8. _云计算学习路线图素材课件,Linux中软件安装的方式
  9. quill变html转化,将Quill Delta转换为HTML
  10. leetcode——面试题 17.10. 主要元素