NOI 2019 省选模拟赛 T1【JZOJ6082】 染色问题(color) (多项式,数论优化)
题面
一根长为 n 的无色纸条,每个位置依次编号为 1,2,3,…,n ,m 次操作,第 i 次操作把纸条的一段区间 [l,r] (l <= r , l,r ∈ {1,2,3,…,n})涂成颜色 i ,最后一定要把纸条涂满颜色,问最终的纸条有多少种可能的模样。
输入为两个数 n,m ,输出为你的答案
m <= n <= 1e6
题解
不考虑先前染的颜色被覆盖这件事情。如果某种颜色在最终的序列中出现了 x 次,那么我们就直接认为在染这种颜色的时候,我们只染了 x 个格子。
但这样一来每次染色的格子就不再是连续的一段了。不过如果我们把给一段格子染色认为是在已被染色的颜色序列中插入一段,那么一切都显得简单而明晰了!
首先我们可以想到一个 DP,
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示纸条长度为 j,强制最后出现 i 种颜色时,这 i 种颜色的方案数(也就是说先不乘
C
(
m
,
i
)
C(m,i)
C(m,i) 之类的),那么有如下转移:
d
p
[
i
]
[
j
]
⋅
(
j
+
1
)
→
d
p
[
i
+
1
]
[
k
]
(
k
>
j
)
dp[i][j]\cdot (j+1)\;\rightarrow\;dp[i+1][k](k>j)
dp[i][j]⋅(j+1)→dp[i+1][k](k>j)
(可以看作是在格子间隙中插入了一段颜色为 i+1 的)
我们最后要求的是
∑
i
=
1
m
d
p
[
i
]
[
n
]
∗
C
(
m
−
1
,
i
−
1
)
\sum_{i=1}^{m}dp[i][n]*C(m-1,i-1)
∑i=1mdp[i][n]∗C(m−1,i−1) 因为最后一种颜色必须出现所以是
C
(
m
−
1
,
i
−
1
)
C(m-1,i-1)
C(m−1,i−1)。
用前缀和优化可以做到 n 方,接下来我们想想怎么优化。
化式子无比艰难,我们不如感性分析一下。看上方的转移,从
d
p
[
0
]
[
0
]
dp[0][0]
dp[0][0] 转移过来,我们首先选了一个数 k > 0 转移到了
d
p
[
1
]
[
k
]
dp[1][k]
dp[1][k],然后还可以再选一个数 k’ > k 来转移到
d
p
[
2
]
[
k
′
]
dp[2][k']
dp[2][k′],此时的贡献为
(
k
+
1
)
(k+1)
(k+1),于是再选个数 k’’ > k’,对
d
p
[
3
]
[
k
′
′
]
dp[3][k'']
dp[3][k′′] 产生
(
k
+
1
)
(
k
′
+
1
)
(k+1)(k'+1)
(k+1)(k′+1) 的贡献…… 对于
d
p
[
i
]
[
n
]
dp[i][n]
dp[i][n] 来说,相当于我们在
[
1
,
n
−
1
]
[1,n-1]
[1,n−1] 中选了
i
−
1
i-1
i−1 个数,把它们都+1,然后乘起来,这样的所有方案的乘积和。
所以,
d
p
[
i
]
[
n
]
dp[i][n]
dp[i][n] 就等于
F
n
−
1
=
∏
i
=
1
n
−
1
(
x
+
(
i
+
1
)
)
F_{n-1}=\prod_{i=1}^{n-1}(x+(i+1))
Fn−1=∏i=1n−1(x+(i+1)) 这个多项式的
n
−
i
n - i
n−i 次项,这里稍微转化理解一下,不难明白,相当于不选产生 1 的贡献,选产生 i+1 的贡献,k 次项系数表示 k 个数不选。
于是可以分治 NTT 做,求出这个多项式,
O
(
n
log
2
n
)
O(n\log^2n)
O(nlog2n),很可惜还是过不了。
实际上我们乘的这 n-1 个多项式是有规律的,我们可以推一推。
假设我们已经求出了
F
t
F_t
Ft ,我们要求
F
2
t
F_{2t}
F2t ,有这个式子:
F
2
t
=
∏
i
=
1
2
t
(
x
+
i
+
1
)
=
∏
i
=
1
t
(
x
+
i
+
1
)
∏
i
=
1
t
(
x
+
(
i
+
t
)
+
1
)
=
F
t
∏
i
=
1
t
(
x
+
(
i
+
t
)
+
1
)
F_{2t}=\prod_{i=1}^{2t}(x+i+1)=\prod_{i=1}^{t}(x+i+1)\prod_{i=1}^{t}(x+(i+t)+1)\\ =F_t\prod_{i=1}^{t}(x+(i+t)+1)
F2t=∏i=12t(x+i+1)=∏i=1t(x+i+1)∏i=1t(x+(i+t)+1)=Ft∏i=1t(x+(i+t)+1)
不妨就设右边那坨为
F
t
′
F_t'
Ft′,那么
F
2
t
=
F
t
⋅
F
t
′
F_{2t}=F_t\cdot F_{t}'
F2t=Ft⋅Ft′ ,我们知道
F
t
′
F_t'
Ft′ 的话就可以 NTT 了,现在来推
F
t
′
F_t'
Ft′:
我们先令
X
=
x
+
t
X = x+t
X=x+t 来换个元,
F
t
′
=
∏
i
=
1
t
(
x
+
i
+
t
+
1
)
=
∏
i
=
1
t
(
(
x
+
t
)
+
i
+
1
)
=
∏
i
=
1
t
(
X
+
i
+
1
)
F_t'=\prod_{i=1}^{t}(x+i+t+1)=\prod_{i=1}^{t}((x+t)+i+1)=\prod_{i=1}^{t}(X+i+1)
Ft′=∏i=1t(x+i+t+1)=∏i=1t((x+t)+i+1)=∏i=1t(X+i+1)
然后会发现它是跟
F
t
F_t
Ft 一样的形式,我们把
F
t
F_t
Ft 的每项系数带入:
F
t
′
=
∑
i
=
0
t
F
t
[
i
]
X
i
=
∑
i
=
0
t
F
t
[
i
]
(
x
+
t
)
i
F_t'=\sum_{i=0}^{t}F_t[i]X^i=\sum_{i=0}^{t}F_t[i](x+t)^i
Ft′=∑i=0tFt[i]Xi=∑i=0tFt[i](x+t)i
利用二项式定理变成这样:
∑
i
=
0
t
F
t
[
i
]
∑
j
=
0
i
x
j
t
i
−
j
C
(
i
,
j
)
\sum_{i=0}^{t}F_t[i]\sum_{j=0}^{i}x^jt^{i-j}C(i,j)
∑i=0tFt[i]∑j=0ixjti−jC(i,j)
换个枚举顺序:
∑
j
=
0
t
x
j
∑
i
=
j
t
F
t
[
i
]
t
i
−
j
C
(
i
,
j
)
\sum_{j=0}^{t}x^j\sum_{i=j}^{t}F_t[i]t^{i-j}C(i,j)
∑j=0txj∑i=jtFt[i]ti−jC(i,j)
我们令
B
[
i
]
=
F
t
[
t
−
i
]
B[i]=F_t[t-i]
B[i]=Ft[t−i] 翻转一下:
∑
j
=
0
t
x
j
∑
i
=
j
t
B
[
t
−
i
]
t
i
−
j
C
(
i
,
j
)
\sum_{j=0}^{t}x^j\sum_{i=j}^{t}B[t-i]t^{i-j}C(i,j)
∑j=0txj∑i=jtB[t−i]ti−jC(i,j)
→
∑
j
=
0
t
x
j
∑
i
=
j
t
B
[
t
−
i
]
t
i
−
j
i
!
j
!
(
i
−
j
!
)
\rightarrow\sum_{j=0}^{t}x^j\sum_{i=j}^{t}B[t-i]t^{i-j}\frac{i!}{j!(i-j!)}
→∑j=0txj∑i=jtB[t−i]ti−jj!(i−j!)i!
右边就变成了一个卷积的形式,最终这样应该更好理解:
F
t
′
=
∑
j
=
0
t
(
1
j
!
⋅
(
∑
i
=
j
t
B
[
t
−
i
]
t
i
−
j
i
!
(
i
−
j
)
!
)
)
⋅
x
j
F_t'=\sum_{j=0}^{t}\left(\frac{1}{j!}\cdot(\sum_{i=j}^{t}B[t-i]t^{i-j}\frac{i!}{(i-j)!})\right)\cdot x^{j}
Ft′=∑j=0t(j!1⋅(∑i=jtB[t−i]ti−j(i−j)!i!))⋅xj
求出它之后我们就可以求出
F
2
t
F_{2t}
F2t 了,这样递归,复杂度
T
(
n
)
=
T
(
n
2
)
+
O
(
n
log
n
)
=
O
(
n
log
n
)
T(n)=T(\frac{n}{2})+O(n\log n)=O(n\log n)
T(n)=T(2n)+O(nlogn)=O(nlogn) ,可以过。
CODE
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1000005
#define DB double
#define LL long long
#define ENDL putchar('\n')
LL read() {
LL f=1,x=0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return x*f;
}
const int MOD = 998244353;
const int proot = 3;
int n,m,i,j,s,o,k;
int dp[MAXN];
int fac[MAXN],inv[MAXN],invf[MAXN];
int C(int n,int m) {
if(m > n || n < 0) return 0;
return fac[n] *1ll* invf[n-m] % MOD *1ll* invf[m] % MOD;
}
int xm[MAXN<<2],rev[MAXN<<2],om;
int qkpow(int a,int b) {
int res = 1;
while(b > 0) {
if(b & 1) res = res *1ll* a % MOD;
a = a *1ll* a % MOD; b >>= 1;
}return res;
}
void NTT(int *s,int n,int op) {
for(int i = 1;i < n;i ++) {
rev[i] = ((rev[i>>1]>>1) | ((i & 1) ? (n>>1):0));
if(rev[i] < i) swap(s[rev[i]],s[i]);
}
om = qkpow(proot,(MOD-1)/n); xm[0] = 1;
if(op<0) om = qkpow(om,MOD-2);
for(int i = 1;i <= n;i ++) xm[i] = xm[i-1] *1ll* om % MOD;
for(int k = 2,t = (n>>1);k <= n;k <<= 1,t >>= 1) {
for(int j = 0;j < n;j += k) {
for(int i = j,l=0;i < j+(k>>1);i ++,l += t) {
int A = s[i],B = s[i+(k>>1)];
s[i] = (A + xm[l] *1ll* B % MOD) % MOD;
s[i+(k>>1)] = (A +MOD- xm[l] *1ll* B % MOD) % MOD;
}
}
}
int invn = qkpow(n,MOD-2);
if(op < 0) for(int i = 0;i < n;i ++) s[i] = s[i] *1ll* invn % MOD;
return ;
}
int A[MAXN<<2],B[MAXN<<2],cc[MAXN<<2];
void solve(int n) {
if(n == 1) {
A[0] = 2;A[1] = 1;return ;
}
int md = n>>1;
solve(md);
int po = 1,le = 1;
while(le <= md*2) le <<= 1;
for(int i = 0;i <= md;i ++) {
B[i] = A[md-i] *1ll* fac[md-i] % MOD;
cc[i] = po *1ll* invf[i] % MOD;
po = po *1ll* md % MOD;
}
NTT(B,le,1);NTT(cc,le,1);
for(int i = 0;i <= le;i ++) B[i] = B[i] *1ll* cc[i] % MOD,cc[i] = 0;
NTT(B,le,-1);
for(int i = md+1;i <= le;i ++) B[i] = 0;
for(int i = 0;i <= md;i ++) B[i] = B[i] *1ll* invf[md-i] % MOD;
for(int i = 0;i+i <= md;i ++) swap(B[i],B[md-i]);
while(le <= n) le <<= 1;
NTT(B,le,1); NTT(A,le,1);
for(int i = 0;i <= le;i ++) A[i] = A[i] *1ll* B[i] % MOD,B[i] = 0;
NTT(A,le,-1); for(int i = n+1;i <= le;i ++) A[i] = 0;
if(n & 1) {
for(int i = n;i > 0;i --) {
A[i] = (A[i] *1ll* (n+1) % MOD + A[i-1]) % MOD;
}
A[0] = A[0] *1ll* (n+1) % MOD;
}
return ;
}
int main() {
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
n = read();m = read();
fac[0] = fac[1] = inv[0] = inv[1] = invf[0] = invf[1] = 1;
for(int i = 2;i <= max(n,m);i ++) {
fac[i] = fac[i-1] *1ll* i % MOD;
inv[i] = (MOD-inv[MOD % i]) *1ll* (MOD/i) % MOD;
invf[i] = invf[i-1] *1ll* inv[i] % MOD;
}
solve(n-1);
int ans = 0;
for(int i = 1;i <= min(n,m);i ++) {
(ans += A[n-i] *1ll* C(m-1,i-1) % MOD) %= MOD;
}
printf("%d",ans);
return 0;
}
NOI 2019 省选模拟赛 T1【JZOJ6082】 染色问题(color) (多项式,数论优化)的更多相关文章
- [NOI.AC省选模拟赛3.23] 染色 [点分治+BFS序]
题面 传送门 重要思想 真的是没想到,我很久以来一直以为总会有应用的$BFS$序,最终居然是以这种方式出现在题目中 笔记:$BFS$序可以用来处理限制点对距离的题目(综合点分树使用) 思路 本题中首先 ...
- 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解
今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...
- NOI.AC省选模拟赛第一场 T1 (树上高斯消元)
link 很容易对于每个点列出式子 \(f_{x,y}=(f_{x,y-1}+f_{x,y}+f_{x,y+1}+f_{x+1,y})/4\)(边角转移类似,略) 这个转移是相互依赖的就gg了 不过你 ...
- 2019.2.25 模拟赛T1【集训队作业2018】小Z的礼物
T1: [集训队作业2018]小Z的礼物 我们发现我们要求的是覆盖所有集合里的元素的期望时间. 设\(t_{i,j}\)表示第一次覆盖第i行第j列的格子的时间,我们要求的是\(max\{ALL\}\) ...
- [NOI.AC省选模拟赛3.31] 附耳而至 [平面图+最小割]
题面 传送门 思路 其实就是很明显的平面图模型. 不咕咕咕的平面图学习笔记 用最左转线求出对偶图的点,以及原图中每个边两侧的点是谁 建立网络流图: 源点连接至每一个对偶图点,权值为这个区域的光明能量 ...
- [NOI.AC省选模拟赛3.23] 集合 [数学]
题面 传送门 一句话题意: 给定$n\leq 1e9,k\leq 1e7,T\leq 1e9$ 设全集$U=\lbrace 1,2,3,...n\rbrace $,求$(min_{x\in S}\lb ...
- [noi.ac省选模拟赛]第12场题解集合
题目 比赛界面. T1 数据范围明示直接\(O(n^2)\)计算,问题就在如何快速计算. 树上路径统计通常会用到差分方法.这里有两棵树,因此我们可以做"差分套差分",在 A 树上对 ...
- [noi.ac省选模拟赛]第10场题解集合
题目 比赛界面. T1 不难想到,对于一个与\(k\)根棍子连接的轨道,我们可以将它拆分成\(k+1\)个点,表示这条轨道不同的\(k+1\)段. 那么,棍子就成为了点与点之间的边.可以发现,按照棍子 ...
- [noi.ac省选模拟赛]第11场题解集合
题目 比赛界面. T1 比较简单.容易想到是求鱼竿的最大独立集.由于题目的鱼竿可以被分割为二分图,就可以想到最大匹配. 尝试建边之后会发现边的数量不小,但联系题目性质会发现对于一条鱼竿,它 ...
随机推荐
- 【动态规划】统计蚂蚁 (ants)
题目 描述 蚂蚁山上有T(1<=T<=1,000)种蚂蚁,标记为1..T,每种蚂蚁有N_i只蚂蚁(1<=N_i<=100),现有A(A<=5000)只蚂蚁,从中选出S,S ...
- 开源流程引擎camunda如何扩展
市场上基于Java语言的开源工作流引擎有:osworkflow.jbpm.activiti.flowable.camunda等,其中osworkflow.jbpm流程引擎已经过时,目前主流的开源 ...
- 在Winform开发中,使用Async-Awati异步任务处理代替BackgroundWorker
在Winform开发中有时候我们为了不影响主UI线程的处理,以前我们使用后台线程BackgroundWorker来处理一些任务操作,不过随着异步处理提供的便利性,我们可以使用Async-Awati异步 ...
- BUUCTF-面具下的flag
面具下的flag 010editor打开发现存在ZIP binwalk -e mianju.jpg 分离压缩包出来 但是存在密码.猜测是伪加密,直接编辑器搜504B0102找到第五组字符组改为00即可 ...
- BUUCTF-小明的保险箱
小明的保险箱 16进制打开可以发现存在一个RAR压缩包,压缩包里面应该就是flag文本 使用ARCHPR破解即可
- 一篇文章带你使用Typescript封装一个Vue组件
一.搭建项目以及初始化配置 vue create ts_vue_btn 这里使用了vue CLI3自定义选择的服务,我选择了ts.stylus等工具.然后创建完项目之后,进入项目.使用快捷命令code ...
- javascript写淡入淡出效果的轮播图
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- UiPath邮件自动化
在UiPath中下载Outlook电子邮件附件Outlook电子邮件自动化教程UiPathRPAhttps://www.bilibili.com/video/BV1oK411L72T 在UiPath中 ...
- 给你准备好了——50道Python面试题集锦(附答案)
Python是目前编程领域最受欢迎的语言.在本文中,我将总结Python面试中最常见的50个问题.每道题都提供参考答案,希望能够帮助你在2019年求职面试中脱颖而出,找到一份高薪工作.这些面试题涉及P ...
- FFT 学习笔记(自认为详细)
引入 什么是 \(\text{FFT}\) ? 反正我看到 \(\text{wiki}\) 上是一堆奇怪的东西. 快速傅里叶变换(英语:Fast Fourier Transform, FFT),是快速 ...