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 ...
随机推荐
- Hibernate对象的三种状态,瞬时态、持久态、游离态
1.瞬时态.(new完一个对象,突然断电,内存中没有此对象) hibernate中什么时候的对象为瞬时态呢,当我们new 一个对象时,还没有save时,它就是瞬时态的,当我们delete一个对象时,它 ...
- [笔记]CodeIgniter的SESSION
由于HTTP协议本身是无状态的,所以当保留某个用户的访问状态信息时,需要客户端有一个唯一标识传给服务端,这个唯一标识就是SESSION ID,存放在客户端的COOKIE中,然后服务端根据该标 ...
- Oracle序列和伪表
创建序列 create sequence sq_teacher_tnostart with 10 从哪一个数字开始increment by 1 每次增长的数字maxvalue 999999999999 ...
- html模拟组织架构横向展开
近期看到不少人有相似的需求.实现组织架构的横向展开,显示.无聊就做了一下.先看下终于的效果图 兼容各大主流浏览器,而且支持IE6.7,8,不同的是排除标签圆角效果外,资源文件:文件下载地址 主流浏览器 ...
- 渐进式 jpg 和 交错式 gif png 提高图片站体验
渐进式 jpg 和 交错式 gif png 提高图片站体验= 渐进式的JPG比原始JPG还要小!! 让图片性感的露给你看~google picasa 和 smashing magazine 都有用到搞 ...
- 单线程和多线程处理1W条数据对比代码
package study.interview; import java.util.ArrayList; import java.util.HashMap; import java.util.Link ...
- 关于layoutparam 请铭记。。。。
//rl_pager 是RelativeLayout findViewById(R.id.rl_pager).setLayoutParams(new RelativeLayout.LayoutPara ...
- Spark在Windows下的环境搭建
本文转载自:http://blog.csdn.net/u011513853/article/details/52865076 由于Spark是用Scala来写的,所以Spark对Scala肯定是原生态 ...
- (转)2009-05-25 22:12 Outlook2007选择发送帐号
本文转载自:http://hi.baidu.com/vugwggogodaenqe/item/c95c6d019457a2d873e676ec outlook2007可以用程序选择发送帐号,其他的版本 ...
- bzoj2783 树
第一行是两个整数N和S,其中N是树的节点数. 第二行是N个正整数,第i个整数表示节点i的正整数. 接下来的N-1行每行是2个整数x和y,表示y是x的儿子. 输出格式: 输出路径节点总和为S的路径数量. ...