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 ...
随机推荐
- Inno Setup 软件封装
例子: ; 脚本用 Inno Setup 脚本向导 生成. ; 查阅文档获取创建 INNO SETUP 脚本文件的详细资料! #define MyAppName "隧道照明系统客户端程序&q ...
- JPA中的Page与Pageable
Page是Spring Data提供的一个接口,该接口表示一部分数据的集合以及其相关的下一部分数据.数据总数等相关信息,通过该接口,我们可以得到数据的总体信息(数据总数.总页数...)以及当前数据的信 ...
- 1106-冒泡算法C程序(语法树)
#include <stdio.h> main() { int i,j,temp; int a[10]; for(i=0;i<10;i++) scanf ("%d,&quo ...
- Python学习思维导图
刚学习Python时,边学边总结的,采用思维导图的形式, 适合回顾使用.内容参考<Python:从入门到实践>一书. 再给出一张Datacamp网站上的一张关于Python基础的总结 ...
- Kafka问题排查(消费者自动关闭)
问题描述: 在消费端能够正常消费到Kafka数据并成功生产到producer topic 中,当将kafka的一台机器关机之后,正常情况下应该是 消费端是不受影响的.因为有还有两 ...
- 转--NLTK的内置函数
NLTK的内置函数 1. 词语索引 (1) concordance函数 给出一个指定单词每一次出现,连同上下文一起显示. >>>text1.concordance('monst ...
- 关于Fragment框架,说的够清晰了。。。
Android4.0-Fragment框架实现方式剖析(一) 分类: Android UI 2012-09-19 18:59 14880人阅读 评论(8) 收藏 举报 android 目录(?)[ ...
- java HttpClient 获取页面Cookie信息
HttpClient client = new HttpClient(); GetMethod get=new GetMethod("http://www.baidu.com"); ...
- /proc目录下文件详解
/proc “文件系统”是一个目录,其中包含的文件层次结构代表了 Linux 内核的当前状态.它允许用户和管理员查看系统的内核视图. /proc 目录中还包含关于系统硬件及任何当前正在运行的程序信息. ...
- Java 8 新特新 工具类 ZonedDateTime
类ZonedDateTime java.lang.Object继承 java.time.ZonedDateTime 所有实现的接口: Serializable,Comparable < Chro ...