[SDOI2015]序列统计

标签: NTT 快速幂


Description

给你一个模m意义下的数集,需要用这个数集生成一个数列,使得这个数列在的乘积为x。

问方案数模\(1004535809\)。

Solution

首先很容易写出一个dp。

\(dp_{i,j}\)数列长度为i,乘积为j的方案数。

这么做是\(O(nm^2)\)的。

所以我们肯定要搞点事情,把n变成logn。

这个数列显然是满足结合律的,并且每次的转移都相同。

于是可以写一个快速幂,把n降为logn。

注意到乘积不太好维护,所以可以用原根来把乘法变成加法。

那么现在问题就变成了,\(dp_{i,j}\)表示数列长度为i,和为j的方案数。

是不是很像一个背包?

注意到每次合并两个背包就是一个卷积,所以我们用NTT维护即可。

最终复杂度。\(O(m\ logm\ logn)\)

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
int sum=0,p=1;char ch=getchar();
while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
if(ch=='-')p=-1,ch=getchar();
while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
return sum*p;
} const int maxn=2e4+20;
const int mod=1004535809; int yg;
int len,m,en,n,to[maxn]; inline int power(int a,int b,int mod)
{
int ans=1;
while(b)
{
if(b & 1)ans=(ll)ans*a%mod;
b>>=1;
a=(ll)a*a%mod;
}
return ans;
} inline void getyg()
{
for(yg=2;yg<=m-1;yg++)
{
int x=m-1,y=x,flg=1;
for(int i=2;i*i<=y;i++)
{
if(x%i)continue;
while(!(y%i))y/=i;
if(power(yg,x/i,m)==1){flg=0;break;}
}
if(y>1)if(power(yg,x/y,m)==1)continue;
if(flg)return;
}
} int rev[maxn],a[maxn],f[maxn],g[maxn]; void NTT(int *p,int opt)
{
REP(i,0,n-1)if(i<rev[i])swap(p[i],p[rev[i]]);
for(int i=1;i<n;i<<=1)
{
int W=power(3,(mod-1)/(i<<1),mod);
for(int j=0;j<n;j+=i<<1)
{
int w=1;
for(int k=j;k<j+i;k++,w=(ll)w*W%mod)
{
int x=p[k],y=(ll)w*p[k+i]%mod;
p[k]=x+y;p[k+i]=x-y;
if(p[k]>=mod)p[k]-=mod;
if(p[k+i]<0)p[k+i]+=mod;
}
}
}
if(opt==-1)
{
reverse(p+1,p+n);
int inv=power(n,mod-2,mod);
REP(i,0,n-1)p[i]=(ll)p[i]*inv%mod;
}
} inline void init()
{
len=read();m=read();en=read();n=read();
getyg();
REP(i,0,m-2)to[power(yg,i,m)]=i;
REP(i,1,n)
{
int x=read();if(!x)continue;
a[i]=to[x],f[a[i]]++;
}
int s=2*(m-1),l=0;
n=1;while(n<s)l++,n<<=1;
REP(i,1,n-1)rev[i]=(rev[i>>1]>>1)| ( (i & 1)<<(l-1));
} inline void doing()
{
//REP(i,0,n-1)printf("%d ",g[i]);puts("");
g[0]=1;
while(len)
{
if(len & 1)
{
NTT(g,1);
NTT(f,1);
REP(i,0,n-1)g[i]=(ll)f[i]*g[i]%mod;
NTT(g,-1);
NTT(f,-1);
REP(i,m-1,n-1)
g[i%(m-1)]=(g[i%(m-1)]+g[i])%mod,g[i]=0;
}
len>>=1;
NTT(f,1);
REP(i,0,n-1)f[i]=(ll)f[i]*f[i]%mod;
NTT(f,-1);
REP(i,m-1,n-1)
f[i%(m-1)]=(f[i%(m-1)]+f[i])%mod,f[i]=0;
}
printf("%d\n",g[to[en]]);
} int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
init();
doing();
return 0;
}

[SDOI2015]序列统计的更多相关文章

  1. BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1017  Solved: 466[Submit][Statu ...

  2. 3992: [SDOI2015]序列统计

    3992: [SDOI2015]序列统计 链接 分析: 给定一个集和s,求多少个长度为n的序列,满足序列中每个数都属于s,并且所有数的乘积模m等于x. 设$f=\sum\limits_{i=0}^{n ...

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

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

  4. 【LG3321】[SDOI2015]序列统计

    [LG3321][SDOI2015]序列统计 题面 洛谷 题解 前置芝士:原根 我们先看一下对于一个数\(p\),它的原根\(g\)有什么性质(好像就是定义): \(g^0\%p,g^1\%p,g^2 ...

  5. [BZOJ3992][SDOI2015]序列统计(DP+原根+NTT)

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1888  Solved: 898[Submit][Statu ...

  6. 【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂

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

  7. BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1155  Solved: 532[Submit][Statu ...

  8. BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)

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

  9. [SDOI2015]序列统计(NTT+求原根)

    题目 [SDOI2015]序列统计 挺好的题!!! 做法 \(f[i][j]\)为第\(i\)个数前缀积在模\(M\)意义下为\(j\) 显然是可以快速幂的:\[f[2*i][j]=\sum\limi ...

随机推荐

  1. Struts2与Ajax数据交互

    写在前面: ajax请求在项目中常常使用,今天就平时掌握的总结一下,关于使用ajax请求到Struts2中的action时,前台页面与后台action之间的数据传递交互问题. 这里我主要记录下自己所掌 ...

  2. linux tpm 测试完整记录,亲测有效。

    没有tpm芯片,采用模拟器的方式来测试. 实验环境:内核版本 3.10.0-327 软件包准备: 内网,没有仓库,自己网上下载: 1. cmake-3.9.6-Linux-x86_64.tar.gz ...

  3. elasticsearch安装ik分词器

    一.概要: 1.es默认的分词器对中文支持不好,会分割成一个个的汉字.ik分词器对中文的支持要好一些,主要由两种模式:ik_smart和ik_max_word 2.环境 操作系统:centos es版 ...

  4. python3 第十八章 - 迭代器与生成器

    1.迭代器(Iterator) 迭代是访问集合元素的一种方式 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退. 迭代器 ...

  5. 爬取西刺网代理ip,并把其存放mysql数据库

    需求: 获取西刺网代理ip信息,包括ip地址.端口号.ip类型 西刺网:http://www.xicidaili.com/nn/ 那,如何解决这个问题? 分析页面结构和url设计得知: 数据都在本页面 ...

  6. python_如何设置文件缓冲类型

    案例: 将文件内容写入到硬件设备时候,使用系统调用,这类IO操作时间长,为了减小IO操作,通常会使用缓冲区(有足够多数据才能调用). 文件缓冲行为分为:全缓冲,行缓冲,无缓冲 如何解决? open(' ...

  7. Traits技法

    扮演"特性萃取机"角色,萃取各个迭代器的特性(迭代器的相应类型) 模板特例化:提供一份template定义式,而其本身仍为templatization 通过class templa ...

  8. sp_getAppLock使用

    sp_getAppLock  获取程序资源锁,简单的说就是调用此函数可以达到我们程序中.NET的lock锁的作用. 作用域是当前数据库下 四个参数: @resource(必填):资源名称,类型nvar ...

  9. redis info详解

    INFO 以一种易于解释(parse)且易于阅读的格式,返回关于 Redis 服务器的各种信息和统计数值. 通过给定可选的参数 section ,可以让命令只返回某一部分的信息: server 部分记 ...

  10. Ajax发送数据