[SDOI2015]序列统计

题目描述

小C有一个集合S,里面的元素都是小于M的非负整数。他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S。小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个。小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi。另外,小C认为这个问题的答案可能很大,因此他只需要你帮助他求出答案mod 1004535809的值就可以了。

输入格式

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

输出格式

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

输入输出样例
输入 #1

4 3 1 2
1 2

输出 #1

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)。

【数据规模和约定】

对于10%的数据,1<=N<=1000;

对于30%的数据,3<=M<=100;

对于60%的数据,3<=M<=800;

对于全部的数据,1<=N<=109,3<=M<=8000,M为质数,1<=x<=M-1,输入数据保证集合S中元素不重复

题解

这题似乎是我做过的第一道多项式题。。

最傻逼的想法:DP

设计状态 f [ i ] [ j ] f[i][j] f[i][j]表示前 i i i个数在 m o d m mod m modm后积为 j j j的方案数

b [ i ] b[i] b[i]表示集合中 i i i是否出现过

转移: f [ i ] [ j ] = ∑ k = 1 m f [ i − 1 ] [ k ] × b [ i n v [ k ] × j m o d m ] f[i][j]=\sum_{k=1}^{m}f[i-1][k]\times b[inv[k]\times j modm] f[i][j]=k=1mf[i1][k]×b[inv[k]×jmodm]

复杂度: O ( n m 2 ) O(nm^2) O(nm2)

然后考虑倍增:

转移: f [ i × 2 ] [ c ] = ∑ a × b ≡ c ( m o d m ) f [ i ] [ a ] × f [ i ] [ b ] f[i\times 2][c]=\sum_{a\times b\equiv c(mod m)}f[i][a]\times f[i][b] f[i×2][c]=a×bc(modm)f[i][a]×f[i][b]

复杂度: O ( m 2 l o g 2 n ) O(m^2log_2n) O(m2log2n)

像我这种蒟蒻做到这一步就跪了,但是大佬们都知道要取离散对数,然后就能NTT了,因为取完对数 ∑ \sum 里的条件就变成加法了,于是就成卷积了,NTT解决。

f ( x ) = ∑ i = 1 m b [ i ] ∗ x l o g m i f(x)=\sum_{i=1}^{m}b[i]*x^{log_mi} f(x)=i=1mb[i]xlogmi

复杂度: O ( m l o g 2 ( m n ) ) O(mlog_2(mn)) O(mlog2(mn))

收获:
  1. 第一道多项式题
  2. 离散对数
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值