3992: [SDOI2015]序列统计

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中的所有元素。

Output

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

Sample Input

4 3 1 2
1 2

Sample Output

8

HINT

【样例说明】
可以生成的满足要求的不同的数列有(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)。
【数据规模和约定】
对于10%的数据,1<=N<=1000;
对于30%的数据,3<=M<=100;
对于60%的数据,3<=M<=800;
对于全部的数据,1<=N<=109,3<=M<=8000,M为质数,1<=x<=M-1,输入数据保证集合S中元素不重复
 

Source

题解:

  利用原根G

  将序列的乘积替换成加法

  想快速幂那般的计算,得到长度为n的序列

  每次NTT加速

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 6e4+, M = 2e2+,inf = 2e9;
int MOD;
inline int muls(int a, int b){
return (long long)a * b % MOD;
}
int power(int a, int b){
int ret = ;
for (int t = a; b; b >>= ){
if (b & )ret = muls(ret, t);
t = muls(t, t);
}
return ret;
}
int cal_root(int mod)
{
int factor[], num = , s = mod - ;
MOD = mod--;
for (int i = ; i * i <= s; i++){
if (s % i == ){
factor[num++] = i;
while (s % i == )s /= i;
}
}
if (s != )factor[num++] = s;
for (int i = ;; i++){
int j = ;
for (; j < num && power(i, mod / factor[j]) != ; j++);
if (j == num)return i;
}
} const LL G = 3LL, P = 1004535809LL;
LL mul(LL x,LL y){
return (x*y-(LL)(x/(long double)P*y+1e-)*P+P)%P;
}
LL qpow(LL x,LL k,LL p){
LL ret=;
while(k){
if(k&) ret=mul(ret,x);
k>>=;
x=mul(x,x);
}
return ret;
}
LL wn[];
void getwn(){
for(int i=; i<=; ++i){
int t=<<i;
wn[i]=qpow(G,(P-)/t,P);
}
}int len;
void NTT_init() {
getwn();
} void NTT(LL y[],int op){
for(int i=,j=len>>,k; i<len-; ++i){
if(i<j) swap(y[i],y[j]);
k=len>>;
while(j>=k){
j-=k;
k>>=;
}
if(j<k) j+=k;
}
int id=;
for(int h=; h<=len; h<<=) {
++id;
for(int i=; i<len; i+=h){
LL w=;
for(int j=i; j<i+(h>>); ++j){
LL u=y[j],t=mul(y[j+h/],w);
y[j]=u+t;
if(y[j]>=P) y[j]-=P;
y[j+h/]=u-t+P;
if(y[j+h/]>=P) y[j+h/]-=P;
w=mul(w,wn[id]);
}
}
}
if(op==-){
for(int i=; i<len/; ++i) swap(y[i],y[len-i]);
LL inv=qpow(len,P-,P);
for(int i=; i<len; ++i) y[i]=mul(y[i],inv);
}
}
LL mo[N],fmo[N],now[N],xx[N],yy[N];
int m;
void cal(LL *x,LL *y,LL *z) {
for(int i = ; i < len; ++i) xx[i] = x[i],yy[i] = y[i];
NTT(xx,);NTT(yy,);
for(int i = ; i < len; ++i) z[i] = xx[i] * yy[i] % P,now[i] = ;
NTT(z,-); for(int i = ; i <= *m-; ++i)
now[mo[i%(m-)]] += z[i],z[i] = ; for(int i = ; i < len; ++i) z[i] = ;
for(int i = ; i <= m-; ++i) {
z[fmo[i]] += now[i];
}
}
LL y[N],ans[N],ny[N],num[N],an[N];
int n,x,s,root,cnt0; int main() {
NTT_init();
scanf("%d%d%d%d",&n,&m,&x,&s);
root = cal_root(m);
for(int i = , t = ; i < m-; ++i,t = t*root%m)
mo[i] = t,fmo[t] = i;
for(int i = ; i <= s; ++i) {
int xx;
scanf("%d",&xx);
if(xx == )
cnt0+=;
else
num[fmo[xx]]+=;
}
if(x == ) {
LL L = (qpow(2LL,cnt0,P) - + P) % P + qpow(2LL,s-cnt0,P)%P;
printf("%lld\n",L%P);
return ;
}
len = ;
int f = ;
while(len <= *m) len<<=;
for(int i = ; i < len; ++i) y[i] = num[i],ans[i] = ;
int j = ;
int chan = ;
while(n) {
if(n&) {
if(f) {
f = ;
for(int i = ; i < len; ++i) ans[i] = y[i];
}
else {
cal(ans,y,ans);
}
}
cal(y,y,y);
n>>=;
}
int l = ;
for(int i = ; i < len; ++i) {
an[mo[i%(m-)]] += ans[i],an[mo[i%(m-)]]%=P;
}
cout<<an[x]<<endl;
return ;
}

BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)的更多相关文章

  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]序列统计

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 2275  Solved: 1090[Submit][Stat ...

  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]序列统计【原根+生成函数+NTT+快速幂】

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

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

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

  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. SQL处理XML

    使用SP_XML_PREPAREDOCUMENT 来读取 Xml 文本. 读取作为输入提供的 XML 文本,然后使用 MSXML 分析器 (Msxmlsql.dll) 对其进行分析,并提供分析后的文档 ...

  2. xcode错误-第三方的东西他不支持

    ld:' /用户/ tanqihong /桌面/金粒子公司/金粒子公司/ Carloans / Carloans /第三/ TongLianPay / lib_release / libAPayLib ...

  3. Tomcat 调优技巧

    Tomcat 调优技巧:1.Tomcat自身调优: ①采用动静分离节约Tomcat的性能: ②调整Tomcat的线程池: ③调整Tomcat的连接器: ④修改Tomcat的运行模式: ⑤禁用AJP连接 ...

  4. POJ1635 树的最小表示法(判断同构)

    Some major cities have subway systems in the form of a tree, i.e. between any pair of stations, ther ...

  5. 洛谷 P 1164 小A点菜

    题目背景 uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种. uim指着墙上的价目表(太低级了没有菜单),说:“随便点”. 题目描述 不过uim由于买了一些辅(e ...

  6. 2-sat问题,输出方案,几种方法(赵爽的论文染色解法+其完全改进版)浅析 / POJ3683

    本文原创于  2014-02-12 09:26. 今复习之用,有新体会,故重新编辑. 2014-02-12 09:26: 2-sat之第二斩!昨天看了半天论文(赵爽的和俉昱的),终于看明白了!好激动有 ...

  7. call 和 apply 方法区别

    在js中call和apply它们的作用都是将函数绑定到另外一个对象上去运行,两者仅在定义参数方式有所区别,下面我来给大家介绍一下call和apply用法. 在web前端开发过程中,我们经常需要改变th ...

  8. 安装配置JDK+Eclipse+Maven、Eclipse里新建Maven Project以及HDFS命令和Java API-课堂内容

    步骤:1.安装JDK→2.安装Eclipse→3.安装Maven→4. Eclipse里配置Maven (下载Windows版本,在Windows里安装使用.) 1.安装配置JDK ①官网下载Java ...

  9. 什么是Hadoop?什么是HDFS?

    [学习笔记] 什么是Hadoop?什么是HDFS?马 克-to-win @ 马克java社区:Hadoop是Apache基金会开发的一个分布式系统基础架构.比如前面我们接触的Spring就是一个开发应 ...

  10. yum gd linux

    32位操作系统安装命令:[root@localhost ~]# yum install php-gd*64位操作系统安装命令:[root@localhost ~]# yum install php-g ...