[题解 LuoguP4491 [HAOI2018]染色
神仙计数题 Orz
先令\(F[k]\)表示出现次数恰好为\(S\)次的颜色恰好有\(k\)中的方案数,那么
\]
怎么求\(F[k]\)呢?一个naive的想法,我指定哪\(k\)种颜色恰好染\(S\)次,然后剩下的\(n-kS\)个位置用剩下的\(m-k\)种颜色随便染
相当与对一个有\(k+1\)种元素的集合(前\(k\)中元素分别有\(S\)个,最后一种元素有\(n-kS\)个)做可重复集合全排列
这个方案数是\(\frac{n!}{(S!)^k(n-kS)!}\)的
剩下的\(n-kS\)个位置又可以用剩下的颜色随便染,所以还要乘上\((m-k)^{n-kS}\)
所以我们得到了一个柿子\(\binom{m}{k}\times\frac{n!}{(S!)^k(n-kS)!}\times (m-k)^{n-kS}\)
从这个柿子也可以看出,合法的颜色种数不会超过\(lim=\min(m,\lfloor n/S\rfloor)\)
然后发现他假了,首先这样得到的并不是恰好有\(k\)种的方案数,其次在后面随便染色的时候我们还可能算上重复的方案,它根本不能称为方案数。
但不要放弃希望,我们把上面的柿子叫做\(G[k]\)好了。考虑怎么用\(F\)算\(G\),又有一个naive的想法枚举合法的颜色有多少个得到这个柿子
\(G[k]=\sum_{i=k}^{lim} F[i]\)
但上面我们说过了,\(G[k]\)可能会算上重复的方案数。
对于一个恰好有\(i\)种颜色满足要求的方案,不难发现在\(G[k]\)中会被重复计算\(\binom{i}{k}\)次(先在\(i\)个颜色中指定\(k\)个然后剩下的随便染,这样可能会染到同一种方案)
所以
\]
发现右边出现了组合数,这恰恰是一个可以二项式反演的柿子,于是反演一波得到
\]
这样就可以得到一个平方的算法了,考虑优化。
先把组合数炸开来
\]
然后
\]
令\(A[i]=i!G[i],B[i]=\frac{(-1)^i}{i!}\),有
\]
这个柿子已经有点可以卷积了,随便翻转\(A\)或者\(B\)都可以,下面翻转\(A\)好了,令翻转\(A[0...lim]\)后得到\(A^T\),那么
\]
将\(A\)与\(B\)卷积,然后\(F[k]\times k!\)就是卷积的第\(lim-k\)项。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (int i=(a);i<(b);++i)
#define per(i,a,b) for (int i=(a)-1;i>=(b);--i)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
typedef double db;
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> VI;
const int NN=1e7+10,N=3e5+10,P=1004535809;
inline int add(int x,int y) {return (x+=y)>=P?x-P:x;}
inline int sub(int x,int y) {return (x-=y)<0?x+P:x;}
inline int normal(int x) {return x<0?x+P:x;}
inline int fpow(int x,int y) {
int ret=1; for(;y;y>>=1,x=1ll*x*x%P)
if(y&1) ret=1ll*ret*x%P;
return ret;
}
const int gn=3,ign=fpow(gn,P-2);
int fac[NN],ifac[NN],inv[NN];
inline int getC(int n,int r) {return 1ll*fac[n]*ifac[n-r]%P*ifac[r]%P;}
namespace Poly {
int rev[N];
inline void init(int n) {
rep(i,0,n) rev[i]=rev[i>>1]>>1|((i&1)?n>>1:0);
}
void ntt(int *f,int n,int flg) {
rep(i,0,n) if(rev[i]<i) swap(f[i],f[rev[i]]);
for(int len=2,k=1;len<=n;len<<=1,k<<=1) {
int wn=fpow(flg==1?gn:ign,(P-1)/len);
for(int i=0;i<n;i+=len)
for(int j=i,w=1;j<i+k;j++,w=1ll*w*wn%P) {
int tmp=1ll*w*f[j+k]%P;
f[j+k]=sub(f[j],tmp),f[j]=add(f[j],tmp);
}
}
if(flg==-1) {
int invn=fpow(n,P-2);
rep(i,0,n+1) f[i]=1ll*f[i]*invn%P;
}
}
}
using Poly::ntt;
void init(int n) {
ifac[0]=ifac[1]=fac[0]=fac[1]=inv[1]=1;
rep(i,2,n+1) {
inv[i]=1ll*inv[P%i]*(P-P/i)%P;
ifac[i]=1ll*ifac[i-1]*inv[i]%P;
fac[i]=1ll*fac[i-1]*i%P;
}
}
int A[N],B[N],W[N];
int main() {
#ifdef LOCAL
freopen("a.in","r",stdin);
#endif
int n,m,s; scanf("%d%d%d",&n,&m,&s);
rep(i,0,m+1) scanf("%d",&W[i]);
init(max(max(n,m),s));
int lim=min(m,n/s);
rep(i,0,lim+1) {
A[i]=1ll*fac[i]*getC(m,i)%P*fac[n]%P*fpow(ifac[s],i)%P
*ifac[n-i*s]%P*fpow(m-i,n-i*s)%P;
B[i]=(i&1)?P-ifac[i]:ifac[i];
}
reverse(A,A+lim+1);
int limit=1; while(limit<=2*lim) limit<<=1; Poly::init(limit);
ntt(A,limit,1),ntt(B,limit,1);
rep(i,0,limit) A[i]=1ll*A[i]*B[i]%P;
ntt(A,limit,-1);
int ans=0;
rep(i,0,m+1) ans=add(ans,1ll*W[i]*A[lim-i]%P*ifac[i]%P);
printf("%d\n",ans);
return 0;
}
[题解 LuoguP4491 [HAOI2018]染色的更多相关文章
- 【题解】[HAOI2018]染色(NTT+容斥/二项式反演)
[题解][HAOI2018]染色(NTT+容斥/二项式反演) 可以直接写出式子: \[ f(x)={m \choose x}n!{(\dfrac 1 {(Sx)!})}^x(m-x)^{n-Sx}\d ...
- 【题解】HAOI2018染色
好坑啊不开心…… 其实这题的想法还是比较简单粗暴的.题目明示恰好xxx,显然排除斜率二分这个玩意儿,那么不就只剩下容斥了嘛…… 令 \(A_{x}\) 为恰好出现了 \(S\) 次的至少有 \(x\) ...
- luoguP4491 [HAOI2018]染色 广义容斥原理 + FFT
非常明显的摆了一个NTT模数.... 题目中求恰好\(k\),那么考虑求至少\(k\) 记\(g(k)\)表示至少\(k\)中颜色出现了恰好\(S\)次 那么,\[g(k) = \binom{M}{k ...
- [洛谷P4491] [HAOI2018]染色
洛谷题目链接:[HAOI2018]染色 题目背景 HAOI2018 Round2 第二题 题目描述 为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可 以抽象为一个长度 ...
- 【LG4491】[HAOI2018]染色
[LG4491][HAOI2018]染色 题面 洛谷 题解 颜色的数量不超过\(lim=min(m,\frac nS)\) 考虑容斥,计算恰好出现\(S\)次的颜色至少\(i\)种的方案数\(f[i] ...
- BZOJ 5306 [HAOI2018] 染色
BZOJ 5306 [HAOI2018] 染色 首先,求出$N$个位置,出现次数恰好为$S$的颜色至少有$K$种. 方案数显然为$a_i=\frac{n!\times (m-i)^{m-i\times ...
- 【BZOJ5306】 [Haoi2018]染色
BZOJ5306 [Haoi2018]染色 Solution xzz的博客 代码实现 #include<stdio.h> #include<stdlib.h> #include ...
- [BZOJ5306] [HAOI2018]染色(容斥原理+NTT)
[BZOJ5306] [HAOI2018]染色(容斥原理+NTT) 题面 一个长度为 n的序列, 每个位置都可以被染成 m种颜色中的某一种. 如果n个位置中恰好出现了 S次的颜色有 K种, 则小 C ...
- 【BZOJ5306】[HAOI2018]染色(NTT)
[BZOJ5306]染色(NTT) 题面 BZOJ 洛谷 题解 我们只需要考虑每一个\(W[i]\)的贡献就好了 令\(lim=min(M,\frac{N}{S})\) 那么,开始考虑每一个\(W[i ...
随机推荐
- Java面向对象编程 -4
声明static属性 static 是一个关键字,这个关键字主要是用来定义属性和方法. static内存分析 在正常开发之中每一个对象都要保存有各自的属性 所以此时程序没有问题 但是如果country ...
- 关于 UIDatePicker 在iOS9 系统上的一个坑
在使用 UIDatePicker时,在iOS9系统上上遇到一个很奇怪的问题,在其他系统版本中没发现,设置年月日格式显示的视图,在iOS9设备上出现中间月份无法显示的问题: 检查代码没问题,这个视图是使 ...
- [运维] 请求 nginx 出现 502 Bad Gateway 的解决方案!
环境: 云服务器镜像 Linux CentOS 7.6 已经安装并成功配置 SSL 的 nginx 1.16.1 成功安装并且可以正常运行的 apache-tomcat-9.0.26 遇到的问题: 在 ...
- mssql-osql
mssql导入单行字段值非常长,或者sql文件非常大,比如上百M或者更大,常规方法是导不进去的,所以推荐下面方式进行导入. osql -S . -U sa -P 123456 -d TS_TEST - ...
- python3.6.5修改print的颜色
开头部分:\033[显示方式;前景色;背景色m +想要输出的内容:\033[0m 注意:开头部分的三个参数:显示方式,前景色,背景色是可选参数,具体参数效果见下文,可以只写其中的某一个:参数 ...
- 阿里云短信接口开发实践(Java
随着互联网的兴起,各行各业的需求都在不断的增加.随着业务的扩大,企业给用户发送短信验证码的业务,也是如火如荼.在这里,calvin给各位开发者推荐阿里云短信平台.原因有二:1.接入较简单,开发成本低 ...
- 在abp core中出现运行项目时EF获取到的appsetting.json或者appsettings.Production.json中的连接字符串为空
原因:有可能是生成的bin或者debug文件夹下没有将appsetting.json或者appsettings.Production.json文件生成过去 解决方法:手动拷贝过去,或者设置成自动生成过 ...
- java_3:JVM、JRE、JDK区别和联系
首先 三者之间存在包含关系JVM + 核心类库 = JREJRE + java开发工具(javac.exe/jar.exe) = JDK 什么是JVM? 我们知道Java语言有一个独特的优点就是可以跨 ...
- MessageBox函数
<Windows程序设计>(第五版)(美Charles Petzold著) https://docs.microsoft.com/zh-cn/windows/desktop/apiinde ...
- heap(堆)
二叉堆: 以前写过二叉堆,但很少使用,快忘了.最近又查了一些关于堆的资料,于是重新熟悉一下这种数据结构. 一个快速又简单的方式建立二叉堆,仅使用简单vector(或者数组也行): #include & ...