Counting
Description
数学老师走啦,英语老师来上课啦
他的性格与众不同,又因为大家都是理科班的学生
他希望大家在数字母的过程中领悟英语的快乐
他用m种字母进行排列组合,
得到了所有不同的,长度为n的字符串
(不需要所有字母都出现在字符串中)
对于每个字符串s
定义C(s)为s中出现次数最多的字母的出现次数
那么问题来了
所有的这些字符集大小为m,长度为n的字符串中
C(s)=k的有多少个呢
Input
一行三个整数n,m,k,分别表示长度,字符集和要求的C(s)
Output
输出一行表示结果
答案对998244353取模
Sample Input
3 2 2
Sample Output
6
HINT
数据保证k≤n
对于10%的数据,1≤n,m≤8
对于30%的数据,1≤n,m≤200
对于50%的数据,1≤n,m≤1000
对于100%的数据,1≤n,m≤50000
样例解释:
假设样例中的两个字母为a,b
则满足条件的有aab,aba,abb,baa,bab,bba六个
Solution
首先把最直观的DP方程列出来。
记\(f[i][j][k]\)为当前考虑到第\(i\)个字母,已经使用了串中的\(j\)个位置,出现最多的字母次数不超过\(k\)的方案数。答案就是\(f[m][n][k]-f[m][n][k-1]\)。
转移方程显然是枚举当前字母使用多少次:
\]
然后可以发现\(k\)十分的冗余,并没有参与转移。也就是说\(k\)仅仅作用于循环范围控制上。
我们尝试把最后一维省掉:\(f[i][j]\)。\(k\)仍然发挥作用,也就是现在的\(f[i][j]\)对应着原来的\(f[i][j][k]\)。
现在看看方程:
f[i][j]&=\sum_{x=0}^k{j\choose x}f[i-1][j-x]\\
&=\sum_{x=0}^k\frac{j!}{x!(j-x)!}f[i-1][j-x]\\
\frac{f[i][j]}{j!}&=\sum_{x=0}^k\;x!\;\frac{f[i-1][j-x]}{(j-x)!}
\end{aligned}
\]
后面显然是一个卷积的形式,并且等号左边的形式和卷积右半边的形式一样。所以可以把每个\(f[i]\)看做一个多项式
\]
转移就是这个多项式和
\]
的卷积。即\(f[n]=f[0]*T^{n}(x)\)
而\(T(x)\)是独立的存在不受其他东西影响,所以将\(T(x)\)用快速幂自卷积一下,再用\(f[0]\)卷积一下就好了。根据定义,\(f[0]=1\),所以相当于直接求\(T(x)\)的\(n\)次方。答案别忘了乘上\(n\)的阶乘。
#include <cstdio>
#include <cstring>
using namespace std;
const int N=50005,MOD=998244353,G=3,B17=131100;
int fact[N],iact[N];
inline void swap(int &x,int &y){x^=y^=x^=y;}
inline int pow(int x,int y){
int res=1;
for(;y;x=1LL*x*x%MOD,y>>=1)
if(y&1) res=1LL*res*x%MOD;
return res;
}
namespace NTT{/*{{{*/
int n,invn,bit,rev[B17],W[B17][2];
void build(){
int b=pow(G,MOD-2);
for(int i=0;i<=17;i++){
W[1<<i][0]=pow(G,(MOD-1)/(1<<i));
W[1<<i][1]=pow(b,(MOD-1)/(1<<i));
}
}
void init(int _n){
for(n=1,bit=0;n<_n;n<<=1,bit++);
invn=pow(n,MOD-2);
for(int i=0;i<n;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void clear(int *a){for(int i=0;i<n;i++)a[i]=0;}
void ntt(int *a,int f){
for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
int u,v,w_n,w;
for(int i=2;i<=n;i<<=1){
w_n=W[i][f==-1];
for(int j=0;j<n;j+=i){
w=1;
for(int k=0;k<i/2;k++){
u=a[j+k]; v=1LL*w*a[j+i/2+k]%MOD;
a[j+k]=(u+v)%MOD; a[j+i/2+k]=(u-v)%MOD;
w=1LL*w*w_n%MOD;
}
}
}
if(f==-1)
for(int i=0;i<n;i++) a[i]=1LL*a[i]*invn%MOD;
}
}/*}}}*/
void ksm(int *x,int y,int n,int *res){
NTT::init((n+1)*2);
NTT::clear(res);
res[0]=1;
for(;y;y>>=1){
NTT::ntt(x,1);
if(y&1){
NTT::ntt(res,1);
for(int i=0;i<NTT::n;i++) res[i]=1LL*res[i]*x[i]%MOD;
NTT::ntt(res,-1);
for(int i=n+1;i<NTT::n;i++) res[i]=0;
}
for(int i=0;i<NTT::n;i++) x[i]=1LL*x[i]*x[i]%MOD;
NTT::ntt(x,-1);
for(int i=n+1;i<NTT::n;i++) x[i]=0;
}
}
int solve(int n,int m,int k){
static int a[B17],b[B17];
memset(a,0,sizeof a);
for(int i=0;i<=k;i++) a[i]=iact[i];
ksm(a,m,n,b);
return 1LL*fact[n]*b[n]%MOD;
}
int main(){
freopen("input.in","r",stdin);
NTT::build();
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
fact[0]=1;
for(int i=1;i<=n;i++) fact[i]=1LL*fact[i-1]*i%MOD;
iact[n]=pow(fact[n],MOD-2);
for(int i=n-1;i>=0;i--) iact[i]=1LL*iact[i+1]*(i+1)%MOD;
int ans=(solve(n,m,k)-solve(n,m,k-1))%MOD;
printf("%d\n",ans<0?ans+MOD:ans);
return 0;
}
Counting的更多相关文章
- 萌新笔记——Cardinality Estimation算法学习(二)(Linear Counting算法、最大似然估计(MLE))
在上篇,我了解了基数的基本概念,现在进入Linear Counting算法的学习. 理解颇浅,还请大神指点! http://blog.codinglabs.org/articles/algorithm ...
- POJ_2386 Lake Counting (dfs 错了一个负号找了一上午)
来之不易的2017第一发ac http://poj.org/problem?id=2386 Lake Counting Time Limit: 1000MS Memory Limit: 65536 ...
- ZOJ3944 People Counting ZOJ3939 The Lucky Week (模拟)
ZOJ3944 People Counting ZOJ3939 The Lucky Week 1.PeopleConting 题意:照片上有很多个人,用矩阵里的字符表示.一个人如下: .O. /|\ ...
- find out the neighbouring max D_value by counting sort in stack
#include <stdio.h> #include <malloc.h> #define MAX_STACK 10 ; // define the node of stac ...
- 1004. Counting Leaves (30)
1004. Counting Leaves (30) A family hierarchy is usually presented by a pedigree tree. Your job is ...
- 6.Counting Point Mutations
Problem Figure 2. The Hamming distance between these two strings is 7. Mismatched symbols are colore ...
- 1.Counting DNA Nucleotides
Problem A string is simply an ordered collection of symbols selected from some alphabet and formed i ...
- uva 11401 Triangle Counting
// uva 11401 Triangle Counting // // 题目大意: // // 求n范围内,任意选三个不同的数,能组成三角形的个数 // // 解题方法: // // 我们设三角巷的 ...
- JSONKit does not support Objective-C Automatic Reference Counting(ARC) / ARC forbids Objective-C objects in struct
当我们在使用JSONKit处理数据时,直接将文件拉进项目往往会报这两个错“JSONKit does not support Objective-C Automatic Reference Coun ...
- iOS开发 JSonKit does not support Objective-C Automatic Reference Counting(ARC)
有使用JSonKit的朋友,如果遇到“JSonKit does not support Objective-C Automatic Reference Counting(ARC)”这种情况,可参照如下 ...
随机推荐
- Netty源码分析第5章(ByteBuf)---->第10节: SocketChannel读取数据过程
Netty源码分析第五章: ByteBuf 第十节: SocketChannel读取数据过程 我们第三章分析过客户端接入的流程, 这一小节带大家剖析客户端发送数据, Server读取数据的流程: 首先 ...
- 【树莓派】crontab的两个问题
1,/var/log下面,没有cron.log日志 root@raspberrypi:/# nano /etc/rsyslog.conf …… …… ############### #### RULE ...
- sqli-labs学习笔记 DAY8
DAY 8 sqli-lab Page-3 sqli-labs lesson 38 What is Stacked injection? https://blog.csdn.net/Fly_hps/a ...
- No.11_功能规格说明书
功能规格说明书 • 基本目标 为用户提供更加便捷和人性化的闹钟提醒服务,以群组为单位规划时间安排与分配,对于个人用户,实现个人的设置闹钟,取消闹钟的操作,这些操作将会上传至数据库,并被同步到所有的客户 ...
- Task 6.2冲刺会议四 /2015-5-17
今天主要是学习并熟悉了C#的开发流程,把他的文件的大体结构和每个组件之间的联系弄清楚之后.开始写服务器部分的内容.学习过程中,感觉网上的资料有些太鱼龙混杂了,不知道该怎么取舍.明天准备完善服务器的功能 ...
- angularJS1笔记-(17)-ng-bind-html指令
angular不推荐大家在绑定数据的时候绑定html,但是如果你非要这么干也并不是不可以的.举个例子: <!DOCTYPE html> <html lang="en&quo ...
- Redis有序集内部实现原理分析
Redis技术交流群481804090 Redis:https://github.com/zwjlpeng/Redis_Deep_Read Redis中支持的数据结构比Memcached要多的多啦,如 ...
- TCP连接 三次握手 四次挥手
前言: TCP协议是面向连接.安全可靠.基于字节流的传输层协议,在进行http协议访问时就用到了tcp连接.在建立TCP连接时需要经历三次握手,断开连接时需要经历四次挥手.在此进行记录. 内容: TC ...
- 关于mysqlbinlog的重要性.
今天在做update更新数据的时候,因为没有统一好需要更新的数据编执行了update操作,所以需要回滚到先前的数据,所以就赶紧去服务器看binlog日志,结果一看binlog竟然没有开启,把我给惊的啊 ...
- Vue 爬坑之路(一)—— 使用 vue-cli 搭建项目 (增补)
cd 指定好安装目录 vue init webpack 项目名称 执行 vue vue list 查看可应用模板 vue init webpack +名字 项目已启动