给定长度为
n
n
n 的数组
a
a
a ,可以进行任意次操作,每次操作选择一个整数
i
∈
[
2
,
n
]
i\in[2,n]
i∈[2,n] 将
a
i
a_i
ai 修改为
a
i
−
a
i
−
1
a_i-a_{i-1}
ai−ai−1
问能否对所有
i
∈
[
2
,
n
]
i\in[2,n]
i∈[2,n] ,使得
a
i
=
0
a_i=0
ai=0 。
题解
从左到右考虑。 若使得
a
1
=
0
a_1=0
a1=0 ,则必须
a
0
∣
a
1
a_0|a_1
a0∣a1 。 若使得
a
2
=
0
a_2=0
a2=0 ,则必须存在
k
∈
[
0
,
a
1
a
0
]
k\in[0,\frac{a_1}{a_0}]
k∈[0,a0a1] ,使得
(
a
1
−
k
∗
a
i
)
∣
a
2
(a_1-k*a_i)|a_2
(a1−k∗ai)∣a2 ,即
a
0
∣
a
2
a_0|a_2
a0∣a2 。 以此类推,必须对于所有
i
∈
[
2
,
n
]
i\in[2,n]
i∈[2,n] ,满足
a
0
∣
a
i
a_0|a_i
a0∣ai ,才存在合法方案。
给定
n
(
1
≤
n
≤
1
0
5
)
,
l
,
r
(
1
≤
l
≤
r
≤
1
0
9
)
n(1 \leq n \leq 10^5),l,r(1 \leq l \leq r \leq 10^9)
n(1≤n≤105),l,r(1≤l≤r≤109) ,构造长为
n
n
n 的数组
a
1
,
a
2
,
.
.
.
,
a
n
(
l
≤
a
i
≤
r
)
a_1,a_2,...,a_n(l \leq a_i \leq r)
a1,a2,...,an(l≤ai≤r) ,使得
g
c
d
(
i
,
a
i
)
gcd(i,a_i)
gcd(i,ai) 均不同。
题解
注意到
g
c
d
(
i
,
a
i
)
∈
[
1
,
i
]
gcd(i,a_i)\in[1,i]
gcd(i,ai)∈[1,i] ,因此若使得
g
c
d
(
i
,
a
i
)
gcd(i,a_i)
gcd(i,ai) 均不同,则必须
g
c
d
(
i
,
a
i
)
=
i
gcd(i,a_i)=i
gcd(i,ai)=i ,即
i
∣
a
i
i|a_i
i∣ai 。
因此对于每个
i
i
i ,在
[
l
,
r
]
[l,r]
[l,r] 区间内寻找是否存在
i
i
i 的倍数即可。
Doremy有
n
n
n 场考试,第
i
i
i 场考试只能在第
i
i
i 天进行,难度为
a
i
a_i
ai 。初始IQ为
q
(
1
≤
q
≤
1
0
9
)
q(1 \leq q \leq 10^9)
q(1≤q≤109) ,每场考试可以选择参加或不参加。
q
>
0
q>0
q>0 时才能参加考试,若参加,则会产生以下影响:
若
a
i
>
q
a_i>q
ai>q ,则
q
q
q 减少
1
1
1
否则不变
求最多可以参加的考试数。
题解
由于不论
a
i
a_i
ai 多少,只要
a
i
>
q
a_i>q
ai>q 都会使得
q
q
q 减少
1
1
1 ,因此贪心考虑,将降智考试全部排在最后即可。
vis := an array of length n
s := a set of edges
function dfs(u):
vis[u] := true
iterate through each edge (u, v) in the order from smallest to largest edge weight
if vis[v] = false
add edge (u, v) into the set (s)
dfs(v)
function findMST(u):
reset all elements of (vis) to false
reset the edge set (s) to empty
dfs(u)
return the edge set (s)
分别判断调用
f
i
n
d
M
S
T
(
1
)
,
f
i
n
d
M
S
T
(
2
)
,
.
.
.
,
f
i
n
d
M
S
T
(
n
)
findMST(1),findMST(2),...,findMST(n)
findMST(1),findMST(2),...,findMST(n) 后,能否得到正确的最小生成树。
题解
首先由于每条边权值不同,因此最小生成树是唯一的。
以最小生成树为基础,若边
(
u
,
v
)
(u,v)
(u,v) 不在最小生成树上,则
u
u
u 到
v
v
v 的链(不包含
u
,
v
u,v
u,v),及链上节点的分支子树上的点作为起点,会得到一个选择了边
(
u
,
v
)
(u,v)
(u,v) 的错误最小生成树。
只有当起点在
u
,
v
u,v
u,v 及其子树内,才会得到不选择边
(
u
,
v
)
(u,v)
(u,v) 的生成树(但也不一定是正确的)。
对于每条不在MST中的边,筛选掉非法的节点即可。
采用LCA+树上差分可以在
O
(
n
log
(
n
)
)
O(n\log(n))
O(nlog(n)) 复杂度内实现。 或者某些神奇的dfs写法,可以在
O
(
n
)
O(n)
O(n) 复杂度内实现。
给定包含
n
(
2
≤
n
≤
2000
)
n(2 \leq n \leq 2000)
n(2≤n≤2000) 个点的树,根节点为
1
1
1 。 树上的顶点构成集合
U
=
{
1
,
2
,
3
,
.
.
.
,
n
}
U=\{1,2,3,...,n\}
U={1,2,3,...,n} 。
每次操作,选择
U
U
U 的一个“部分虚树”
T
T
T ,然后替换掉原有的
U
U
U 。
T
T
T 是
U
U
U 的“部分虚树”,当且仅当
T
⊂
U
,
T
≠
U
T \subset U,T\neq U
T⊂U,T=U ,且
∀
i
,
j
∈
T
,
L
C
A
(
i
,
j
)
∈
T
\forall i,j\in T,LCA(i,j) \in T
∀i,j∈T,LCA(i,j)∈T 。
求对于
[
1
,
n
−
1
]
[1,n-1]
[1,n−1] 范围内每个整数
k
k
k ,恰好
k
k
k 次操作后,有多少种不同的方法使得
U
=
{
1
}
U=\{1\}
U={1} 。
答案对
p
(
1
0
8
≤
p
≤
1
0
9
+
9
)
p(10^8 \leq p \leq 10^9+9)
p(108≤p≤109+9) 取模。
假设忽略
T
≠
U
T\neq U
T=U 的条件,即
T
⊆
U
T\subseteq U
T⊆U ,每次操作可以不删除任何点,以便进行DP转移。
设
d
p
x
,
i
dp_{x,i}
dpx,i 表示将
x
x
x 节点为根的子树在恰好
i
i
i 步后全部被删除的方案数。注意最后删除的节点不一定是
x
x
x 节点。
设
S
u
m
x
,
i
Sum_{x,i}
Sumx,i 表示将
x
x
x 节点为根的子树在
i
i
i 步之内全部被删除的方案数。有
S
u
m
x
,
i
=
∑
j
=
1
i
d
p
x
,
i
Sum_{x,i}=\sum_{j=1}^{i}{dp_{x,i}}
Sumx,i=j=1∑idpx,i
如果
x
x
x 最后在第
i
i
i 步才被删除,则方案数为
D
x
,
i
=
∏
u
∈
S
o
n
x
S
u
m
u
,
i
D_{x,i}=\prod_{u\in Son_x}{Sum_{u,i}}
Dx,i=u∈Sonx∏Sumu,i
如果
x
x
x 在之前就被删除,考虑枚举最后个被删除的点在
u
∈
S
o
n
x
u\in Son_x
u∈Sonx 为根的子树中,此时其他儿子为根的子树中的点,必定在
x
x
x 之前被删除,枚举
x
x
x 在第
j
j
j 次操作后被删除。方案数为
∑
u
∈
S
o
n
x
d
p
u
,
i
∑
j
=
1
i
−
1
∏
v
∈
S
o
n
x
,
v
≠
x
S
u
m
v
,
j
=
∑
u
∈
S
o
n
x
d
p
u
,
i
∑
j
=
1
i
−
1
D
x
,
j
S
u
m
u
,
j
\begin{align*} &\sum_{u\in Son_x}{dp_{u,i}\sum_{j=1}^{i-1}{\prod_{v\in Son_x,v \neq x}{Sum_{v,j}}}}\\ &=\sum_{u\in Son_x}{dp_{u,i}\sum_{j=1}^{i-1}{\frac{D_{x,j}}{Sum_{u,j}}}} \end{align*}
u∈Sonx∑dpu,ij=1∑i−1v∈Sonx,v=x∏Sumv,j=u∈Sonx∑dpu,ij=1∑i−1Sumu,jDx,j
综上,得到DP转移式
d
p
x
,
i
=
D
x
,
i
+
∑
u
∈
S
o
n
x
d
p
u
,
i
∑
j
=
1
i
−
1
D
x
,
j
S
u
m
u
,
j
dp_{x,i}=D_{x,i}+\sum_{u\in Son_x}{dp_{u,i}\sum_{j=1}^{i-1}{\frac{D_{x,j}}{Sum_{u,j}}}}
dpx,i=Dx,i+u∈Sonx∑dpu,ij=1∑i−1Sumu,jDx,j
特别的,对于根节点
1
1
1 ,由于必须
1
1
1 号点最后删除,因此转移式为
d
p
1
,
i
=
D
1
,
i
dp_{1,i}=D_{1,i}
dp1,i=D1,i 。
以上可以用树形DP在
O
(
n
2
)
O(n^2)
O(n2) 复杂度内求解。
但是
d
p
1
,
k
dp_{1,k}
dp1,k 并不是最终解法,因为一开始忽略了
T
≠
U
T\neq U
T=U 的条件,即每次操作可以不删除任何点。
设
a
n
s
i
ans_i
ansi 表示真正的答案,考虑枚举
d
p
1
,
i
dp_{1,i}
dp1,i 中,共有
j
j
j 步是合法的,
i
−
j
i-j
i−j 步是不删除任何点的方案。
d
p
1
,
i
=
∑
j
=
0
i
C
i
j
a
n
s
j
dp_{1,i}=\sum_{j=0}^i{C_i^j}ans_j
dp1,i=j=0∑iCijansj
变换下,则有
a
n
s
i
=
d
p
1
,
i
−
∑
j
=
0
i
−
1
C
i
j
a
n
s
j
ans_i=dp_{1,i}-\sum_{j=0}^{i-1}C_i^j ans_j
ansi=dp1,i−j=0∑i−1Cijansj
可以在
O
(
n
2
)
O(n^2)
O(n2) 复杂度内求解出所有的
a
n
s
i
ans_i
ansi 。
#include<bits/stdc++.h>#definedebug(...)fprintf(stderr,__VA_ARGS__)#define__FILE(x)\freopen(#x".in","r",stdin);\freopen(#x".out","w",stdout)#defineLLlonglongconstint MX =2000+23;
LL MOD;usingnamespace std;intread(){char k =getchar();int x =0;while(k <'0'|| k >'9') k =getchar();while(k >='0'&& k <='9') x = x *10+ k -'0',k =getchar();return x;}int head[MX],tot =1;structedge{int node ,next;}h[MX <<1];voidaddedge(int u ,int v ,int flg =1){// if(flg) debug("%d %d\n" ,u ,v);
h[++tot]=(edge){v ,head[u]},head[u]= tot;if(flg)addedge(v ,u ,false);}int n ,dp[MX][MX],S[MX][MX],suf[MX][MX],pre[MX][MX];voiddapai(int x ,int f){int ch =0;for(int i = head[x],d ; i ; i = h[i].next){if((d = h[i].node)== f)continue;dapai(d ,x);}for(int i = head[x],d ; i ; i = h[i].next){if((d = h[i].node)== f)continue;++ch;for(int j =0; j <= n ;++j){
suf[ch][j]= pre[ch][j]= S[d][j];}}if(!ch){for(int i =1; i <= n ;++i){
dp[x][i]=1% MOD;
S[x][i]=(S[x][i -1]+ dp[x][i])% MOD;}return;}for(int j =0; j <= n ;++j){for(int i =1; i <= ch ;++i)
pre[i][j]=1LL* pre[i][j]* pre[i -1][j]% MOD;for(int i = ch ; i >=1;--i)
suf[i][j]=1LL* suf[i][j]* suf[i +1][j]% MOD;}for(int i =1; i <= n ;++i) dp[x][i]= pre[ch][i];if(x !=1)for(int i = head[x],d ,c =0; i ; i = h[i].next){if((d = h[i].node)== f)continue;++c;
LL sum =0;for(int mx =1; mx <= n ;++mx){
dp[x][mx]=(dp[x][mx]+ sum * dp[d][mx])% MOD;
sum =(sum +1LL* pre[c -1][mx]* suf[c +1][mx])% MOD;}}for(int i =1; i <= ch ;++i)for(int j =0; j <= n ;++j)
suf[i][j]= pre[i][j]=1% MOD;for(int i =1; i <= n ;++i)
S[x][i]=(S[x][i -1]+ dp[x][i])% MOD;}int C[MX][MX];voidinit(){for(int i =0; i < MX ;++i) C[i][0]=1% MOD;for(int i =1; i < MX ;++i)for(int j =1; j < MX ;++j)
C[i][j]=(C[i -1][j -1]+ C[i -1][j])% MOD;}intmain(){
n =read(),MOD =read();init();for(int i =0; i < MX ;++i)for(int j =0; j < MX ;++j)
suf[i][j]= pre[i][j]=1% MOD;for(int i =2; i <= n ;++i){addedge(read(),read());// addedge(rand() % (i - 1) + 1 ,i);}dapai(1,0);for(int i =1; i < n ;++i){
LL ans =0;for(int j =1; j <= i ;++j){
ans +=((i - j)&1?-1LL:1LL)* C[i][j]* dp[1][j]% MOD;}
ans =(ans % MOD + MOD)% MOD;printf("%lld%c",ans ," \n"[i == n]);}return0;}