[2018集训队作业][UOJ450] 复读机 [DP+泰勒展开+单位根反演]
题面
思路
本文中所有$m$是原题目中的$k$
首先,这个一看就是$d=1,2,3$数据分治
d=1
不说了,很简单,$m^n$
d=2
先上个$dp$试试
设$dp[i][j]$表示前$i$个复读机用掉了$j$个机会,注意这个东西最后求出来的是分配方案,还要乘以一个$n!$
$dp[i][j]=\sum_{k=0}^j [d|k]\binom{n-j+k}{k}dp[i-1][j-k]$
$dp[i][j]=\sum_{k=0}^j [d|k]\frac{(n-j+k)!}{(n-j)!k!}dp[i-1][j-k]$
$(n-j)!dp[i][j]=\sum_{k=0}^j [d|k]\frac{1}{k!}(n-j+k)!dp[i-1][j-k]$
我们令生成函数$A(x)=\sum_{i=0}{\infty}[d|i]\frac{xi}{i!}$,$B_i(x)=\sum{j=0}^{\infty}(n-j)!dp[i][j]$
那么可以发现$B_{i+1}(x)=B_i(x)\ast A(x)$
也就是答案等于$A^m(x)$的第$n$项系数
我们看这个$A(x)$的形式,发现它下面有一堆阶乘,不由得让我们联想到泰勒展开
(我也不知道这个是怎么联想的不过就这样吧我会再写一篇博客解释的23333)
我们发现$ex=\sum_{i=0}{\infty}\frac{xi}{i!}$,同时$e{-x}=\sum_{i=0}^{\infty} (-1)^i \frac{x^i}{i!}$
那么易得$A(x)=\frac{ex+e{-x}}{2}$
所以$Am(x)=(\frac{ex+e{-x}}{2})m=\frac{1}{2m}\sum_{i=0}m \binom{m}{i}e{(2i-m)x}$
然后我们考虑$n$次项系数,发现最外面应该最后乘上去的$n!$和里面的$\frac{1}{n!}$抵消了,上面$e$的幂剩下的系数是$2i-m$
这样我们可以得到答案的表达式$ANS=\sum_{i=0}^m \binom{m}{i} (2i-m)$
d=3
emmm
我们亲爱的$e$好像用不了了
但是我们这个时候有一个神秘的东西:单位根反演!
单位根反演的公式是:$[d|i]=\frac{1}{d}\sum_{j=0}{d-1}\omega_d{ij}$
其中的$\omega_d^j$表示$d$阶单位根的$j$次方
我们代入上面的公式里面得到:
$A(x)=\sum_{i=0}{\infty}\sum_{j=0}{d-1}\frac{1}{d}\omega_d{ij}\frac{xi}{i!}$
$A(x)=\frac{1}{d}\sum_{i=0}{d-1}e{\omega_dix}$
其实可以看到上面的$d=2$就是这个式子的特殊情况
那么$d=3$怎么搞呢?
我们可以发现模数$19491001$是一个3的倍数+1的形式,那么必然存在一个三阶单位负数根根$g$(考虑费马小定理即可)
我们把这个原根求出来,然后两次暴力展开二项式定理,最后可以得到:
$Am(x)=\frac{1}{3m}\sum_{i=0}^m \sum_{j=0}^{m-i} \binom{m}{i}\binom{m-i}{j}e{(i+gj+g2(m-i-j))x}$
然后就$O(m^2\log m)$做完了
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#define MOD 19491001
#define ll long long
using namespace std;
inline ll read(){
ll re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
inline void add(ll &a,ll b){
a+=b;
if(a>=MOD) a-=MOD;
}
inline ll qpow(ll a,ll b){
ll re=1;
while(b){
if(b&1) re=re*a%MOD;
a=a*a%MOD;b>>=1;
}
return re;
}
ll n,m,d,f[1000010],finv[1000010],inv[1000010],g=7,inv3,w1,w2;
void init(){
ll i,len=1000000;
f[0]=f[1]=finv[0]=finv[1]=inv[1]=1;
for(i=2;i<=len;i++) f[i]=f[i-1]*i%MOD;
finv[len]=qpow(f[len],MOD-2);
for(i=len;i>2;i--) finv[i-1]=finv[i]*i%MOD;
for(i=2;i<=len;i++) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
}
inline ll C(ll x,ll y){
return f[x]*finv[y]%MOD*finv[x-y]%MOD;
}
int main(){
n=read();m=read();d=read();
ll i,j;ll ans=0,tmp;init();
inv3=qpow(3,MOD-2);
w1=qpow(g,(MOD-1)/3);
w2=w1*w1%MOD;
if(d==1) cout<<qpow(m,n)<<'\n';
if(d==2){
for(i=0;i<=m;i++){
add(ans,C(m,i)*qpow((2*i-m+MOD)%MOD,n)%MOD);
}
cout<<ans*qpow(qpow(2,m),MOD-2)%MOD<<'\n';
}
if(d==3){
for(i=0;i<=m;i++){
for(j=0;j<=m-i;j++){
tmp=(i+w1*j+w2*(m-i-j))%MOD;
add(ans,C(m,i)*C(m-i,j)%MOD*qpow(tmp,n)%MOD);
}
}
cout<<ans*qpow(qpow(3,m),MOD-2)%MOD<<'\n';
}
}
[2018集训队作业][UOJ450] 复读机 [DP+泰勒展开+单位根反演]的更多相关文章
- uoj450 【集训队作业2018】复读机(生成函数,单位根反演)
uoj450 [集训队作业2018]复读机(生成函数,单位根反演) uoj 题解时间 首先直接搞出单个复读机的生成函数 $ \sum\limits_{ i = 0 }^{ k } [ d | i ] ...
- 处女座与复读机 DP
题目链接:https://ac.nowcoder.com/acm/contest/327/G 题意:给你两个字符串序列,让你根据第二个序列判断是不是 复读机,复读机会有以下特征 1. 将任 ...
- 【做题】UOJ450 - 复读机——单位根反演
原文链接 https://www.cnblogs.com/cly-none/p/UOJ450.html 题意:请自行阅读. 考虑用生成函数来表示答案.因为秒之间是有序的,所以这应当是个指数生成函数.故 ...
- UOJ450 复读机
题意:n个位置,k种颜色.求有多少种方案使得每种颜色恰出现d的倍数次. 解:d=1就快速幂,n,k很小就DP,记得乘组合数来分配位置. d = 2 / 3的时候,考虑生成函数. f(x) = ∑[d ...
- [2018集训队作业][UOJ424] count [笛卡尔树+括号序列+折线法+组合数学]
题面 请务必不要吐槽我的标签 传送门 思路 一个很重要的结论:原序列的一组同构的解等价于同一棵拥有$n$个节点的笛卡尔树 注意笛卡尔树的定义:父亲节点是区间最值,并且分割区间为左右部分 所以如果两个序 ...
- 【UOJ#450】【集训队作业2018】复读机(生成函数,单位根反演)
[UOJ#450][集训队作业2018]复读机(生成函数,单位根反演) 题面 UOJ 题解 似乎是\(\mbox{Anson}\)爷的题. \(d=1\)的时候,随便怎么都行,答案就是\(k^n\). ...
- UOJ#450. 【集训队作业2018】复读机 排列组合 生成函数 单位根反演
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ450.html 题解 首先有一个东西叫做“单位根反演”,它在 FFT 的时候用到过: $$\frac 1 ...
- UOJ #450. 【集训队作业2018】复读机
前置知识单位根反演自己去浅谈单位根反演看(此外可能需要一定的生成函数的姿势) 首先一看\(d\)这么小,那我们来分类讨论一下吧 当\(d=1\)时,显然答案就是\(k^n\) 当\(d=2\)时,如果 ...
- 【UOJ#450】[集训队作业2018] 复读机
题目链接 题目描述 群里有\(k\)个不同的复读机.为了庆祝平安夜的到来,在接下来的\(n\)秒内,它们每秒钟都会选出一位优秀的复读机进行复读.非常滑稽的是,一个复读机只有总共复读了\(d\)的倍数次 ...
随机推荐
- NB-IOT移植移动onenet基础通信套件之Object_ID,实例ID,资源ID
1. 访问是按照分层的,Object_ID/实例ID/资源ID,对应每一层ID的数据类型,目前是分为3层,一个实例下面可以有多个实例id,对下面的数据结构来说,如果是资源ID的话,类型只能是asBuf ...
- android学习十一 高级调试分析功能
1.debug 功能列表 2.ddms功能( 内存检查,线程检查,视图层次分析) 3.跟踪代码 TraceView 4.命令行工具 adb 5.策略检查StrictMode
- 【JAVA】关于java中 类.class.getResource("/").getPath()获取路径有空格的问题
写了一个web工程,在本地测试正确,但是部署到服务器上就出现错误.原因是读取不到配置文件. 后来从打印出来的文件路径中发现是用Java的class.getResource("/") ...
- HDU - 6440(费马小定理)
链接:HDU - 6440 题意:重新定义加法和乘法,使得 (m+n)^p = m^p + n^p 成立,p是素数.,且satisfied that there exists an integer q ...
- JS里点击事件判断是否 触发了节点 和给标签添加class属性
$("#activityType").click(function(e){ if(e.target==$("#bb")[0]){ var bb=document ...
- JAVA基础学习之路(五)数组的定义及使用
什么是数组:就是一堆相同类型的数据放一堆(一组相关变量的集合) 定义语法: 1.声明并开辟数组 数据类型 数组名[] = new 数据类型[长度]: 2.分布完成 声明数组:数据类型 数组名 [] = ...
- HTML/JSP中一些单书名号标签的用途<%-- --%><!-- --><%@ %><%! %><% %><%= %>
注释 <%-- --%>是(JSP)隐式注释,不会在页面显示的注释 <!-- -->是(Html)显示注释,会在JSP页面显示 关于注释还有单行隐式注释//和多行隐式注释/* ...
- 查找 二叉树中 k1 到 k2区间的节点
vector<int> res; int key1, key2; void traverse(TreeNode * root){//采用前序遍历 if(root == NULL) retu ...
- jstat命令
jstat命令使用 jstat命令可以查看堆内存各部分的使用量,以及加载类的数量.命令的格式如下: jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数] 注意:使用的jdk版本是 ...
- CP文件覆盖问题
# \cp -r -a aaa/* /bbb[这次是完美的,没有提示按Y.传递了目录属性.没有略过目录]