2019-9-2
哇,我初三啦!
2019-9-7
感觉我打了场假赛,A,B很假,打的时候人也很假
C挺有意思的
给你一颗树,每个点的权值为0或1
每次你可以选定一个点u
对于满足 x 到 v 的路径上所有碎片的状态值与 x 的状态值相同 的那些点v 状态值都取反(0变1,1变0)
求最少操作次数,使的最后每个点的状态值相等
n
⩽
5
∗
1
0
5
n\leqslant 5*10^5
n⩽5∗105
考虑树的直径d,每次操作最多减2
我们要让它为0,至少需要
⌊
d
+
1
2
⌋
\lfloor \frac{d+1}{2} \rfloor
⌊2d+1⌋次
怎么构造!
将链的中点作为根即可!
2019-9-8
真,被打爆了!
怎么A这么傻逼自己都想不出来
一颗n点的树上给你m条链
每个点度数不超过10
问最多安排多少条链
使得链之间不会相交(对于边而言)
n
⩽
500
,
m
⩽
n
∗
(
n
−
1
)
2
n\leqslant 500,m\leqslant \frac{n*(n-1)}{2}
n⩽500,m⩽2n∗(n−1)
多组询问
T
⩽
100
,
∑
n
⩽
18000
T\leqslant 100,\sum n\leqslant 18000
T⩽100,∑n⩽18000
这道题,可以很明显看出一个性质
肯定存在一个最优解,对于每棵子树都是最优解
考虑维护
f
i
f_i
fi表示子树i的最优解
h
i
h_i
hi表示i为最优解时的可用节点
然后随便搞搞就好了(利用度数为10进行匹配)
2019-9-10
又打了一场假赛
三题挂了两题
好东西
2019-9-11
自闭了,C真的做不出啊
你有两个长度都为N的01字符串A和B。A中的1的个数和B中的1的个数相等。
题意
你想通过以下方式把A变成B:
- 设a1,a2,…,ak是所有A中的1的下标。
- 设b1,b2,…,bk是所有B中的1的下标。
- 将a1,a2,…,ak随机排序,每种排列出现的概率都是1k!,这一步会产生k!种不同的结果。
- 将b1,b2,…,bk随机排序,每种排列出现的概率都是1k!,这一步会产生k!种不同的结果。
- 对于所有1≤i≤k,依次交换Aai和Abi。
记P为这样搞完之后A和B变得相等的概率。显然,P×(k!)2是个整数,你需要计算这个整数对998244353取模后的值。
A,B为0,1串,至少一个1
长度小于等于10000
解法
把该题目当成图论来理解
swap(a,b)在a,b间连边
设x个公共1,y个“独”1
那么对于一种方案(不管能不能把A变B)会形成y条链,每条链的端点分别是两个y之一
那,如何判断一个方案能不能把A变B
问题的关键在于它能否合理地处理链
你会发现,每条链的交换顺序只能是唯一的,所以合法必定满足这个顺序
所以我们考虑求链的方案数
设i个公共1,j个非公共,
d
p
i
,
j
dp_i,j
dpi,j表示此时链的方案数,考虑编号
则
d
p
i
,
j
=
d
p
i
−
1
,
j
∗
i
∗
j
+
d
p
i
,
j
−
1
∗
j
∗
j
dp_{i,j}=dp_{i-1,j}*i*j+dp_{i,j-1}*j*j
dpi,j=dpi−1,j∗i∗j+dpi,j−1∗j∗j
最后考虑环的时候随便乘上一些系数就好了
然而,你觉得复杂度就是这样的吗,不,你错了!
要知道,世界上有一种东西,叫做多项式!
多项式吼啊!但我们要怎么用它!
令
f
i
,
j
=
d
p
i
,
j
i
!
j
!
f_{i,j}=\frac{dp_{i,j}}{i!j!}
fi,j=i!j!dpi,j
然后
f
i
,
j
=
f
i
−
1
,
j
∗
j
+
f
i
,
j
−
1
∗
j
f_{i,j}=f_{i-1,j}*j+f_{i,j-1}*j
fi,j=fi−1,j∗j+fi,j−1∗j
每到达一个新点,乘上它的纵坐标
这个可以表示成若干个形如
1
1
−
i
x
\frac{1}{1-ix}
1−ix1的乘积的某项系数
于是分治FFT+多项式求逆即可
O
(
n
l
o
g
2
n
2
)
O(nlog_2n^2)
O(nlog2n2)
cao,不是说多项式的复杂度都是一个log的吗,你在骗我
当然,我们有一个log的优秀做法
大概是推出另外一个dp式子,然后发现它可以表示成一个多项式的若干次幂
于是,当然不是分治啦,exp和ln就行了
好像有一道agc神奇的题目,记录一下
对于一个串S
翻转它的一个区间[l,r]得到一个新串
问可以得到多少个不同的区间
答案是有多少对
(
i
,
j
)
(i,j)
(i,j)
满足
S
i
!
=
S
j
S_i!=S_j
Si!=Sj
因为新串(若不等于S)所确定的旋转中心只有一个
2019-9-12
复习了一下差分约束
摘自yww大爷的博客
如果只有
a
i
≤
a
j
+
d
ai≤aj+d
ai≤aj+d 的约束,就可以直接上差分约束。
如果有
a
i
+
a
j
≤
d
ai+aj≤d
ai+aj≤d 的约束,考虑整张图黑白染色,使得同色点之间只有差的约束,异色点之间只有和的约束,然后把白色的点的值取反,就可以跑差分约束了。
白色的点值取反,不影响表示它们之间的差
2019-9-14
T2很好玩
给定一个整数N,请你求出有多少字符集为1到K之间整数的字符串,使得该字符串可以由一个长度为N的回文串循环移位后得到。
考虑一下一个回文串循环移位得到的字符串
这会有个最小周期
采用减去因数的方式容斥
如果其中有回文串
必然该周期是偶数,且只有一个
因为循环t次与周期d-t次是reverse的关系
且周期内没有两个相同的串
做完撒花
2019-9-15
看看T2
题意
有一棵N个点,顶点标号为1到N的树。N−1条边中的第i条边连接顶点ai和bi。
每条边在初始时被染成蓝色。高桥 将进行N−1次操作,来把这棵蓝色的树变成红色的树。
- 选一条仅包含蓝色边的简单路径,并删除这些边中的一条。
- 然后在路径的两个端点中间连一条红色的边。
他的目标是,对于每一个i,都有一条红色的边连接ci和di。
现在请你判断是否可能达成他的目标。
n ⩽ 1 0 5 n\leqslant 10^5 n⩽105
考虑最后加入的红边
一定在蓝树上也是一条边
于是从后往前考虑这些红边
选一条蓝红交集
然后将这条边的两端顶点合并即可
T3
当你发现dp的状态有点多的时候
考虑是不是有一些冗余状态
启发式合并欢迎您
2019-9-17
状态不是很好了,不过加油,好好总结一下!
T2挺神仙的
题意:n堆糖果
每次你可以进行一下两个操作中的一个P:
1.删除个数最大(有多个选一个)的那一堆
2.给所有堆的糖果个数都减1
n
⩽
1
0
5
,
a
i
⩽
1
0
9
n\leqslant 10^5,a_i\leqslant 10^9
n⩽105,ai⩽109
怎么做呢?
图形法+找规律,算是长见识了
如果将
a
i
a_i
ai从大到小排序
每次的操作相当于删除最左边的列或删除最下面一行
令
b
i
,
j
b_{i,j}
bi,j表示删除
[
1
,
i
)
[1,i)
[1,i)列
[
1
,
j
)
[1,j)
[1,j)行时先后手必胜
0后手,1先手
那么边界的值可以很好的算出来
且对角线
(
x
,
y
)
−
(
x
+
1
,
y
+
1
)
(x,y)-(x+1,y+1)
(x,y)−(x+1,y+1)上的b值一样
是不是特别好
于是弄到(1,1)所在的对角线末尾(也就是边界上)的b值即可
O
(
n
l
o
g
2
n
)
O(nlog_2n)
O(nlog2n)
T3也是蛮有意思的
题意:给你两颗树(点编号均为1~n)A,B和上面的点X,Y
交替移动X,Y或不移动(操作次序如上)
X想要尽量完相遇,Y想要尽量早相遇
输出答案(相遇的时间,操作一次算一个时间单位)
无限时间则输出-1
解法:遇到这种题,不妨想一下如何判-1
一种情况是存在X在A上相连的边在B上的距离不小于3
以此为突破点,我们继续考虑
那么,判掉这种情况后,我们不妨考虑答案操作序列的情形
肯定是Y抓到X
如果X最后选择移动,选择待在原地肯定不会差
这样又给了我们一个启发
如果我们对于一个点u,考虑X是否可以通过某种方式到达,且到达后不会被Y抓到(是对Y随后进行的单次操作而言)
很好!如果能进行无限次操作,意味着可以到达一个点u,在A上有"边权"大于等于3的边与它相邻!
如果将B树以Y为根
那么Y及其相邻的点就像一个大蜘蛛
它会如何抓到X
显然,抓到前X只能移动1,2的距离(在B树上)
那么归纳假设当前X在它子树内(不包括该点Y)
X移动到它的父亲,儿子
Y往它的方向走即可(还有可能X傻逼地撞上Y)
X移动到它的父亲的父亲
也许Y往上一走,也许仍然选择往它的儿子走
X移动到它的兄弟,儿子的儿子
Y往下移动,赶尽杀绝
这样,我们形象地描述Y对X的追赶环节
好了,我们发现上面Y对X的追赶建立在X一直没走边权为大于等于3的边
那么我们将A中边权大于等于3的边删掉
与Y仍然联通的点形成了一棵新树M
考虑M中的每个u能不能到达
根据上面Y对X的追赶不难得出
如果一个点u想要被到达,不要走回头路,也就是X应该在A上直接走X到u的最短路
如果一个点u可以被到达,那么它在A上的所有祖先也可以被到达
fine!
关于u可以被到达的充分必要条件,看代码,结合Y对X的追赶不难理解
若可以到达M的边界且M的大小不等于n,那么就可以走无限步
好了,我们成功判断了可不可以走无穷步
那,要是有限步呢…
根据刚才的讨论,有限步的话
操作序列的最后一项不妨选等待,换句话说,“等死”
那那些点可以选择等待啊?没错,就是那些u
设u到Y的距离为dis2,到X的距离为dis1
d
i
s
<
d
i
s
2
dis<dis2
dis<dis2
那么对于任何一种到u的操作路径
由于当中的路径(长度为len)不会被抓
所以在B上它会到dep为len的位置,且
l
e
n
<
d
i
s
2
len<dis2
len<dis2
然后此时“等死”,Y从dep走到了dis2,时间为dis22
所以我们刚才论证了什么?任意一种这样的操作路径如果存在,那么时间会为dis22
而这种操作路径肯定存在,对应题设,取X在A上到u的最短路径即可
完结撒花!咋感觉我废话一堆
对于这种题目,应该加上一份代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,X,Y;
#define Maxn 200010
int Ans=0;
struct Graph{
int head[Maxn],v[Maxn<<1],nxt[Maxn<<1],tot=0;
int fa[Maxn][18],dep[Maxn];
void add_edge(int s,int e){
tot++;v[tot]=e;nxt[tot]=head[s];head[s]=tot;
tot++;v[tot]=s;nxt[tot]=head[e];head[e]=tot;
}
void dfs(int u,int f){
fa[u][0]=f;
for(int i=1;i<=17;++i)fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=nxt[i])
if(v[i]^f){
dep[v[i]]=dep[u]+1;
dfs(v[i],u);
}
}
void go_up(int &k,int d){
for(int i=17;i>=0;--i)
if(d&(1<<i))k=fa[k][i];
}
int LCA(int a,int b){
if(dep[a]>dep[b])go_up(a,dep[a]-dep[b]);
if(dep[a]<dep[b])go_up(b,dep[b]-dep[a]);
if(a==b)return a;
for(int i=17;i>=0;--i)
if(fa[a][i]!=fa[b][i]){
a=fa[a][i];
b=fa[b][i];
}
return fa[a][0];
}
int Dis(int a,int b){
int lca=LCA(a,b);
return dep[a]+dep[b]-2*dep[lca];
}
}A,B;
void solve(int u,int f){
if(A.dep[u]>=B.dep[u])return;
if(Ans!=-1)Ans=max(Ans,B.dep[u]*2);
for(int i=A.head[u];i;i=A.nxt[i])
if(A.v[i]^f){
solve(A.v[i],u);
if(B.Dis(u,A.v[i])>=3)Ans=-1;
}
}
inline void rd(int &x){
x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
}
int main(){
rd(n);rd(X);rd(Y);
int s,e;
for(register int i=1;i<n;++i){
rd(s);rd(e);
A.add_edge(s,e);
}
for(register int i=1;i<n;++i){
rd(s);rd(e);
B.add_edge(s,e);
}
A.dfs(X,0);
B.dfs(Y,0);
solve(X,0);
printf("%d\n",Ans);
return 0;
}
2019-9-18
复习一下笛卡尔树
void Build_Tree(){
for(int i=1;i<=n;++i){
last=0;
while(top){
if(h[st[top]]>h[i]){
if(ch[st[top]][1])ch[i][0]=ch[st[top]][1];
ch[st[top]][1]=i;
break;
}
last=st[top];
top--;
}
if(!top&&last)ch[i][0]=last;
st[++top]=i;
}
}
int query(int root,int l,int r)
{
while(root<l||root>r)
root= root<l? rs[root]:ls[root];
return root;
}//h[root]为区间最大值
感觉今天的比赛不难
T1是三道题中最难的,而自己开场比赛选择去肝它
肝是肝出来了,但是花了三个小时
比较感人
然后1h中花了30min想出T3,没时间写了
T2最后也没写,其实跟T3一样简单
总之,这场比赛反映了我几个问题:
1.不会挑题,当前题感太差。例如T3这道题目,照理来说30min内应该想出来。现在最好是开场把每道题目都看一遍,每道题目先花一个10min想一想(这期间有没有思路很关键)。总之,还是多做题,找对题感,提高自己的下限(我想题目的下限实在是太低了),能开场秒掉套路题和一些思维难度低的思维题(最好想出这些题目不要超过30min,这是我要做的基本下限,也是这个学期的集训目标)。如果发现3道题都不会,最好每道先打一下暴力吧,然后一道道地肝下去。
2.代码能力有待提高今天码T1竟然花了我100min,其实,加上对拍,最好要在1h内完成这一切
3.Bless all
三道题目的做法都讲一下吧
A:这种题目,做法没必要讲了,主要记住一个套路,(x,y)的点可以考虑将x,y坐标当成二分图的两个部分,然后进行连边。
B:推出dp式子,然后FFT,挺套路的
C.其实最好写一下自己的做题思路
考虑一下一条S-T的路径
肯定有个xmin和xmax
然后只要在x在xmin和xmax中更新即可得到答案
于是一些点的xmin和xmax肯定有交集
把它们放在一起更新肯定不错
优化复杂度
所以这启示我们去分治
考虑当前xmin和xmax是否包含mid
于是更新一下
如果不包含
可以把它分成两个子问题
完美
O
(
H
W
l
o
g
2
H
W
l
o
g
2
H
+
Q
W
l
o
g
2
H
)
O(HWlog_2{HW}log_2H+QWlog_2H)
O(HWlog2HWlog2H+QWlog2H)
2019-9-20
今天的题目还是很神奇的,其实蛮水的!
主要是我要加快推题的速度!打代码的速度!
set的操作考虑势能分析
φ
(
a
b
)
=
φ
(
a
)
φ
(
b
)
(
a
,
b
)
φ
(
(
a
,
b
)
)
\varphi(ab)=\frac{\varphi(a)\varphi(b)(a,b)}{\varphi((a,b))}
φ(ab)=φ((a,b))φ(a)φ(b)(a,b)
2019-9-21
欢乐场
欢乐找规律
欢乐推结论
欢乐做神题(反向思考)
2019-9-23
糟糕场
t1还是值得总结一下的
选K个区间,有顺序,使得每个区间的数加1(原本为0),然后所有数不超过T的方案数。
n
,
K
,
T
⩽
40
n,K,T\leqslant 40
n,K,T⩽40
考虑从括号括号匹配的思路去考虑
但是,你会发现无序的很难统计,无需转成有序更难统计,因为需要乘上组合数
于是,把左右括号先放在K个括号中更好
多出来的左括号也要放
t3的话,自己应该能做出来,但是考场的时候为什么不敢朝这个方向想,自闭了