Luogu 4491 [HAOI2018]染色
BZOJ 5306
考虑计算恰好出现$s$次的颜色有$k$种的方案数。
首先可以设$lim = min(m, \left \lfloor \frac{n}{s} \right \rfloor)$,我们在计算的时候只要算到这个$lim$就可以了。
设$f(k)$表示出现$s$次的颜色至少有$k$种的方案数,则
$$f(k) = \binom{m}{k}\binom{n}{ks}\frac{(ks)!}{(s!)^k}(m - k)^{n - ks}$$
就是先选出$k$个颜色和$ks$个格子放这些颜色,这样子总的方案数是全排列除以限排列,剩下的颜色随便放。
处理一下组合数,整个$f$可以在$O(nlogn)$时间内算出来。
设$g(k)$表示出现$s$次的颜色刚好有$k$种的方案数,考虑到对于$\forall i < j$,$g(j)$在$f(i)$中被计算了$\binom{j}{i}$次,所以有
$$f(k) = \sum_{i = k}^{lim}\binom{i}{k}g(i)$$
直接二项式反演回来,
$$g(k) = \sum_{i = k}^{lim}(-1)^{i - k}\binom{i}{k}f(i)$$
拆开组合数,
$$g(k) = \sum_{i = k}^{lim}(-1)^{i - k}\frac{i!}{k!(i - k)!}f(i) = \frac{1}{k!}\sum_{i = k}^{lim}\frac{(-1)^{i - k}}{(i - k)!}(f(i) * (i!))$$
设$A(i) = f(i) * (i!)$,$B(i) = \frac{(-1)^{i}}{i!}$
$$g(k)* (k!) = \sum_{i = k}^{lim}A(i)B(i - k)$$
咕,并不是卷积。
把$B$翻转,再设$B'(i) = B(lim - i)$
$$g(k)* (k!) = \sum_{i = k}^{lim}A(i)B'(lim + k - i)$$
注意到$A*B'$的第$lim + k$项的系数是$\sum_{i = 0}^{lim + k}A(i)B'(lim + k - i)$,但是需要满足
$$ 0 \leq i \leq lim$$
$$ 0 \leq lim + k - i \leq lim $$
$$k \leq i \leq lim$$
刚好满足。
时间复杂度$O(n + mlogm)$。
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
typedef vector <ll> poly; const int N = 1e7 + ;
const int M = 1e5 + ; int n, m, s;
ll w[M], fac[N], ifac[N], f[M], g[M], sum[M]; inline void deb(poly c) {
for (int i = ; i < (int)c.size(); i++)
printf("%lld%c", c[i], " \n"[i == (int)c.size() - ]);
} namespace Poly {
const int L = << ;
const ll P = 1004535809LL; int lim, pos[L]; template <typename T>
inline void inc(T &x, T y) {
x += y;
if (x >= P) x -= P;
} template <typename T>
inline void sub(T &x, T y) {
x -= y;
if (x < ) x += P;
} inline void reverse(poly &c) {
for (int i = , j = (int)c.size() - ; i < j; i++, j--) swap(c[i], c[j]);
} inline ll fpow(ll x, ll y) {
ll res = ;
for (; y > ; y >>= ) {
if (y & ) res = res * x % P;
x = x * x % P;
}
return res;
} inline void prework(int len) {
int l = ;
for (lim = ; lim < len; lim <<= , ++l);
for (int i = ; i < lim; i++)
pos[i] = (pos[i >> ] >> ) | ((i & ) << (l - ));
} inline void ntt(poly &c, int opt) {
c.resize(lim, );
for (int i = ; i < lim; i++)
if (i < pos[i]) swap(c[i], c[pos[i]]);
for (int i = ; i < lim; i <<= ) {
ll wn = fpow(, (P - ) / (i << ));
if (opt == -) wn = fpow(wn, P - );
for (int len = i << , j = ; j < lim; j += len) {
ll w = ;
for (int k = ; k < i; k++, w = w * wn % P) {
ll x = c[j + k], y = c[j + k + i] * w % P;
c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
}
}
} if (opt == -) {
ll inv = fpow(lim, P - );
for (int i = ; i < lim; i++) c[i] = c[i] * inv % P;
}
} inline poly mul(const poly x, const poly y) {
poly u = x, v = y, res;
prework(x.size() + y.size() - );
ntt(u, ), ntt(v, );
for (int i = ; i < lim; i++) res.push_back(u[i] * v[i] % P);
ntt(res, -);
res.resize(x.size() + y.size() - );
return res;
} } using Poly :: P;
using Poly :: fpow;
using Poly :: mul;
using Poly :: inc;
using Poly :: reverse; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > ''|| ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void prework(int len) {
fac[] = ;
for (int i = ; i <= len; i++) fac[i] = fac[i - ] * i % P;
ifac[len] = fpow(fac[len], P - );
for (int i = len - ; i >= ; i--) ifac[i] = ifac[i + ] * (i + ) % P;
} inline ll getC(int x, int y) {
return fac[x] * ifac[y] % P * ifac[x - y] % P;
} int main() {
read(n), read(m), read(s);
for (int i = ; i <= m; i++) read(w[i]); int rep = min(m, n / s);
prework(max(n, m)); for (int i = ; i <= rep; i++)
f[i] = getC(m, i) * getC(n, i * s) % P * fac[i * s] % P * fpow(ifac[s], i) % P * fpow(m - i, n - i * s) % P; /* for (int i = 0; i <= rep; i++)
printf("%lld%c", f[i], " \n"[i == rep]); */ poly a, b;
a.resize(rep + , ), b.resize(rep + , );
for (int i = ; i < rep + ; i++) {
a[i] = f[i] * fac[i] % P;
b[i] = ifac[i];
if (i & ) b[i] = (P - b[i]) % P;
}
reverse(b); // deb(a), deb(b); poly c = mul(a, b); // deb(c); /* for (int i = rep; i >= 0; i--) {
sum[i] = sum[i + 1];
inc(sum[i], c[i]);
} for (int i = 0; i <= rep; i++)
printf("%lld%c", sum[i], " \n"[i == rep]); */ ll ans = ;
for (int i = ; i <= rep; i++) {
g[i] = ifac[i] * c[rep + i] % P;
inc(ans, w[i] * g[i] % P);
} printf("%lld\n", ans);
return ;
}
Luogu 4491 [HAOI2018]染色的更多相关文章
- luogu P4491 [HAOI2018]染色
传送门 这一类题都要考虑推式子 首先推出题目要求的式子,枚举正好有\(s\)个颜色的种类(范围\([0,p=min(\lfloor\frac{n}{s}\rfloor,m)]\)),然后对于后面的颜色 ...
- [洛谷P4491] [HAOI2018]染色
洛谷题目链接:[HAOI2018]染色 题目背景 HAOI2018 Round2 第二题 题目描述 为了报答小 C 的苹果, 小 G 打算送给热爱美术的小 C 一块画布, 这块画布可 以抽象为一个长度 ...
- [BZOJ5306] [HAOI2018]染色(容斥原理+NTT)
[BZOJ5306] [HAOI2018]染色(容斥原理+NTT) 题面 一个长度为 n的序列, 每个位置都可以被染成 m种颜色中的某一种. 如果n个位置中恰好出现了 S次的颜色有 K种, 则小 C ...
- 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 ...
- 【LG4491】[HAOI2018]染色
[LG4491][HAOI2018]染色 题面 洛谷 题解 颜色的数量不超过\(lim=min(m,\frac nS)\) 考虑容斥,计算恰好出现\(S\)次的颜色至少\(i\)种的方案数\(f[i] ...
- [Luogu 2486] SDOI2011 染色
[Luogu 2486] SDOI2011 染色 树剖水题,线段树维护. 详细题解不写了. 我只想说我写的线段树又变漂亮了qwq #include <algorithm> #include ...
- Luogu P2486 [SDOI2011]染色(树链剖分+线段树合并)
Luogu P2486 [SDOI2011]染色 题面 题目描述 输入输出格式 输入格式: 输出格式: 对于每个询问操作,输出一行答案. 输入输出样例 输入样例: 6 5 2 2 1 2 1 1 1 ...
- 【题解】[HAOI2018]染色(NTT+容斥/二项式反演)
[题解][HAOI2018]染色(NTT+容斥/二项式反演) 可以直接写出式子: \[ f(x)={m \choose x}n!{(\dfrac 1 {(Sx)!})}^x(m-x)^{n-Sx}\d ...
随机推荐
- php 递归读取目录
看到很多面试题有这个,今天有机会写了一下. 要注意的是: 在opendir这个函数用完后,要注意closedir,因为安全问题,打开的目录依然存在于内存中,在并发情况下最好关闭,不然容易被破坏. &l ...
- 20155319 2016-2017-2 《Java程序设计》第六周学习总结
20155319 2016-2017-2 <Java程序设计>第六周学习总结 教材学习内容总结 ==第十章 输入/输出== 10.1 InputStream与OutputStream 10 ...
- Redis学习笔记-安装篇(Centos7)
1.安装 这里使用源代码安装的方式,如果你希望使用yum或者rpm包安装的方式,可以百度一下,安装方法可谓多如牛毛. # 下载安装包 # wget http://download.redis.io/r ...
- PAT 1012 数字分类 C语言
给定一系列正整数,请按要求对数字进行分类,并输出以下5个数字: A1 = 能被5整除的数字中所有偶数的和: A2 = 将被5除后余1的数字按给出顺序进行交错求和,即计算n1-n2+n3-n4...: ...
- bootstrap 在超小屏布局时使用 clearfix
bootstrap 在超小屏布局时使用 clearfix 先看案例,一共四个 div,使用 col-xs-6, 所以在特别小型设备上时会变成两行. 不过我们发现如果第一个 div 内容多了后会变成如下 ...
- 【转】foxmail邮箱我已进清理了为什么还是说我的邮箱已满
原文网址:http://zhidao.baidu.com/link?url=YmX_tBenMVsCopjljd80e2Jwvh7H8GnVSrDLeKKBNQkh_Ty50IsX5eAIy4P_64 ...
- wiremock 模拟服务接口提供前端使用
前后端分离同步开发时,如果前端需要等后端把接口都开发完了再去动工的话,项目周期会拉长. 以前开发时,一般前期是先把接口文档写的差不多了,要么是让前端自己构造模拟数据,要么是后端在开个控制器专门提供模拟 ...
- C# 播放器, 收藏
C#写了一个调用libvlc api实现的万能视频播放器 http://www.cnblogs.com/haibindev/archive/2011/12/21/2296173.html 引用库 ht ...
- 2019第十届蓝桥杯C/C++
这是我第一次参加蓝桥杯比赛,比完后,有点低于预期,自己的发挥低于预期,赛事水准也低于预期. 教室里面很多同学的电脑出现问题,举办学校也没有完善的应急方案,有一部分同学11点钟才可以做题. 附题目pdf ...
- Eclipse下使用PySpark报Could not find valid SPARK_HOME while searching
主要是Eclipse下需要多一步配置,就是需要加上SPARK_HOME的系统变量. 首先,在Windows的环境变量中加入SPARK_HOME 然后,在Eclipse的配置中加入这个环境变量: Win ...