[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\)的倍数次 ...
随机推荐
- VINS(八)初始化
首先通过imu预积分陀螺仪和视觉特征匹配分解Fundamental矩阵获取rotationMatrix之间的约束关系,联立方程组可以求得外参旋转矩阵: 接下来会检测当前frame_count是否达到W ...
- 跨平台编译Go程序(交叉编译)
作用:比如你手头只有Mac系统,而你的用户有Linux和Windows的,他们也想用,你可以通过交叉编译出Linux和Windows上的可执行文件给他们用 (1)首先进入go/src 源码所在目录,执 ...
- javasript 字符串 数组操作
Javascript中经常涉及到对字符串和数组的处理,今天总结一下具体的用法 一 操作字符串 String对象有很多函数,可以以不同的方式访问和操作字符串,具体方法如下: charAt(index ...
- 对JSON的理解
JSON语法: JSON是一种结构化数据,它是一种数据格式 JSON可以概括为三种类型:简单值.对象.数组 注意:JSON不支持变量.函数和对象实例 一.JSON简单值 包括字符串.数值.布尔值.和n ...
- 「日常训练」Duff in the Army (Codeforces Round #326 Div.2 E)
题意(CodeForces 588E) 给定一棵\(n\)个点的树,给定\(m\)个人(\(m\le n\))在哪个点上的信息,每个点可以有任意个人:然后给\(q\)个询问,每次问\(u\)到\(v\ ...
- HTML 常见的 DOCTYPE 声明
<!DOCTYPE> 声明必须是 HTML 文档的第一行,位于 <html> 标签之前. <!DOCTYPE> 声明不是 HTML 标签:它是指示 web 浏览器关 ...
- jmeter关联三种常用方法
在LR中有自动关联跟手动关联,但在我看来手动关联更准确,在jmeter中,就只有手动关联 为什么要进行关联:对系统进行操作时,本次操作或下一次操作对服务器提交的请求,这参数里边有部分参数需要服务器返回 ...
- Unity Lighting - Lighting overview 照明概述
Lighting overview 照明概述 In order to calculate the shading of a 3D object, Unity needs to know the ...
- Python 关键字参数和可变参数
关键字参数 如果你有一些具有许多参数的函数,而你又希望只对其中的一些进行指定,那么你可以通过命名它们来给这些参数赋值——这就是python关键字参数(Keyword Arguments)——我们使用命 ...
- lintcode671 循环单词
循环单词 The words are same rotate words if rotate the word to the right by loop, and get another. Cou ...