Description

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

小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:给定整数\(x\),求所有可以生成出的,且满足数列中所有数的乘积\(mod\;M\)的值等于\(x\)的不同的数列的有多少个。小C认为,两个数列\(\lbrace A_{i} \rbrace\)和\(\lbrace B_{i} \rbrace\)不同,当且仅当至少存在一个整数\(i\),满足\(A_{i} \ne B_{i}\)。另外,小C认为这个问题的答案可能很大,因此他只需要你帮助他求出答案\(mod\;1004535809\)的值就可以了。

Input

一行,四个整数,\(N,M,x,\mid S \mid\),其中\(\mid S \mid\)为集合\(S\)中元素个数。第二行,\(\mid S \mid\)个整数,表示集合\(S\)中的所有元素。

Output

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

Sample Input

4 3 1 2

1 2

Sample Output

8

HINT

对于\(10\%\)的数据,\(1 \le N \le 1000\);

对于\(30\%\)的数据,\(3 \le M \le 100\);

对于\(60\%\)的数据,\(3 \le M \le 800\);

对于全部的数据,\(1 \le N \le 10^{9}\),\(3 \le M \le 8000\),\(M\)为质数,\(1 \le x \le M-1\),输入数据保证集合\(S\)中元素不重复。

这题让我知道了原根有什么用。

由于\(M\)是质数,所以\(M\)一定有原根\(G\)。我们只要知道\(1 \sim M-1\)在\(mod \; M\)意义下\(G\)的离散对数就可以把乘法化成了加法。

有了这个之后,我们就可以得到一个生成多项式。观察模数\(1004535809 = 2^{21} \times 479+1\),所以可以使用NTT(快速数论变换,就是把FFT的单位复根变成\(1004535809\)的原根)+快速幂。(把这个题目告诉rhl,rhl直接秒,我太弱了TAT)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
using namespace std; #define gg (3)
#define rhl (1004535809)
#define maxm (16010)
typedef long long ll;
int n,m,x,S,G,tot,factor[maxm],pos[maxm],e[25],ine[25]; inline ll qsm(ll a,ll b,int c)
{
ll ret = 1;
for (;b;b >>= 1,(a *= a) %= c) if (b & 1) (ret *= a) %= c;
return ret;
} struct node
{
int a[maxm*2],len;
inline node() { memset(a,0,sizeof(a)); } inline void NTT(int loglen,int len,int on)
{
for (int i = 0,j,t,p;i < len;++i)
{
for (j = 0,t = i,p = 0;j < loglen;++j,t >>= 1) p <<= 1,p |= t & 1;
if (p < i) swap(a[p],a[i]);
}
for (int s = 1,k = 2;s <= loglen;++s,k <<= 1)
{
int wn; if (on) wn = e[s]; else wn = ine[s];
for (int i = 0;i < len;i += k)
{
int w = 1;
for (int j = 0;j < (k >> 1);++j,w = (ll)wn*w%rhl)
{
int u = a[i+j],v = (ll)w*a[i+j+(k>>1)]%rhl;
a[i+j] = u+v; if (a[i+j] >= rhl) a[i+j] -= rhl;
a[i+j+(k>>1)] = u-v; if (a[i+j+(k>>1)] < 0) a[i+j+(k>>1)] += rhl;
}
}
}
if (!on)
{
int inv = qsm(len,rhl-2,rhl);
for (int i = 0;i < len;++i) a[i] = (ll)a[i]*inv%rhl;
}
} friend inline node operator *(node x,node y)
{
int loglen = 0,len;
for (;(1<<loglen)<x.len+y.len;++loglen); len = 1<<loglen;
x.NTT(loglen,len,1); y.NTT(loglen,len,1);
for (int i = 0;i < (1<<loglen);++i) x.a[i] = (ll)x.a[i]*y.a[i]%rhl;
x.NTT(loglen,len,0);
while (len&&(len >= m||!x.a[len-1]))
{
x.a[(len-1)%(m-1)] += x.a[len-1],x.a[--len] = 0;
if (x.a[len%(m-1)] >= rhl) x.a[len%(m-1)] -= rhl;
}
x.len = len;
return x;
}
}pa; inline bool check(int g)
{
for (int i = 1;i <= tot;++i) if (qsm(g,(m-1)/factor[i],m) == 1) return false;
return true;
} int main()
{
freopen("3992.in","r",stdin);
freopen("3992.out","w",stdout);
scanf("%d %d %d %d",&n,&m,&x,&S);
for (int i = 2,p = m-1;p > 1;++i)
if (!(p % i))
{
factor[++tot] = i;
while (!(p % i)) p /= i;
}
for (int i = 1;i < m;++i) if (check(i)) { G = i; break; }
for (int i = 0,now = 1;i < m-1;++i,(now *= G)%=m) pos[now] = i;
for (int i = 1;i < 20;++i) e[i] = qsm(gg,(rhl-1)>>i,rhl),ine[i] = qsm(e[i],rhl-2,rhl);
for (int i = 1,a;i <= S;++i) { scanf("%d",&a); if (a) pa.a[pos[a]]++; } pa.len = m-1;
node ans; ans.a[0] = 1; ans.len = 1;
for (;n;n >>= 1,pa = pa*pa)
if (n & 1) ans = ans*pa;
printf("%d",ans.a[pos[x]]);
fclose(stdin); fclose(stdout);
return 0;
}

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

  1. Bzoj 4403: 序列统计 Lucas定理,组合数学,数论

    4403: 序列统计 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 328  Solved: 162[Submit][Status][Discuss] ...

  2. bzoj 4403 序列统计 卢卡斯定理

    4403:序列统计 Time Limit: 3 Sec  Memory Limit: 128 MB Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调 ...

  3. BZOJ 4403: 序列统计 数学 lucas

    4403: 序列统计 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4403 Description 给定三个正整数N.L和R,统计长度在 ...

  4. [BZOJ 4403]序列统计

    Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量.输出答案对10^6+3取模的结果. Input 输入第一行包含一个整数T,表示数据组 ...

  5. BZOJ 4403 序列统计(Lucas)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4403 [题目大意] 给定三个正整数N.L和R,统计长度在1到N之间, 元素大小都在L到 ...

  6. bzoj 4403: 序列统计【lucas+组合数学】

    首先,给一个单调不降序列的第i位+i,这样就变成了单调上升序列,设原来数据范围是(l,r),改过之后变成了(l+1,r+n) 在m个数里选长为n的一个单调上升序列的方案数为\( C_m^n \),也就 ...

  7. bzoj 4403 序列统计——转化成组合数的思路

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4403 先说说自己的想法吧. 设f[ i ][ j ]表示当前在倒数第 i 个位置,当前和后面 ...

  8. [BZOJ 3992][SDOI2015]序列统计

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

  9. [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)

    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...

随机推荐

  1. myeclipse开发代码颜色搭配保护视力

    废话不多说,这个东西主要是为了保护视力的,另外我也挺喜欢上边的颜色搭配的,今天特拿出来分享.直接上图

  2. android intent 隐式意图和显示意图(activity跳转)

    android中的意图有显示意图和隐式意图两种, 显示意图要求必须知道被激活组件的包和class 隐式意图只需要知道跳转activity的动作和数据,就可以激活对应的组件 A 主activity  B ...

  3. (转载)equals与==

    引言:从一个朋友的blog转过来的,里面解决了两个困扰我很久的问题.很有久旱逢甘霖的感觉. 概述:        A.==可用于基本类型和引用类型:当用于基本类型时候,是比较值是否相同:当用于引用类型 ...

  4. JDK中DNS缓存的分析

    在JAVA中使用InetAddress.getByName(String host) 方法来获取给定hostname的IP地址.为了减少DNS解析的请求次数,提高解析效率,InetAddress中提供 ...

  5. Java基础知识强化之集合框架笔记49:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)按照总分从高到低输出到控制台

    1. 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩)按照总分从高到低输出到控制台: 分析: A: 定义学生类    B: 创建一个TreeSet集合       C: 总分从高到底如何实现 ...

  6. [iOS 开发] Xcode常见报错及解决办法

    报错一: 在iOS7的真机运行时,弹出错误:App installation failed. There was an internal API error. 如图 解决办法: 在Xcode -> ...

  7. IHttpModule实现URL重写

    1.用自定义IHttpModule实现URL重写 一般来说,要显示一些动态数据总是采用带参数的方式,比如制作一个UserInfo.aspx的动态页面用于显示系统的UserInfo这个用户信息表的数据, ...

  8. GitHub详细教程

    GitHub详细教程 Table of Contents 1 Git详细教程 1.1 Git简介 1.1.1 Git是何方神圣? 1.1.2 重要的术语 1.1.3 索引 1.2 Git安装 1.3 ...

  9. Java根据ip地址获取Mac地址,Java获取Mac地址

    Java根据ip地址获取Mac地址,Java获取Mac地址 >>>>>>>>>>>>>>>>>&g ...

  10. WEB系统开发方向

    1. UI框架:要可以结合jquery+自定义服务器控件开发一套UI框架: 2.WEB报表设计器:用js开发一套可以自定义报表设计器: 3.WEB自定义表单+工作流设计器: 4.WEB打印组件: 5. ...