GDKOI 总结
Day1
原题+水题???只有235。
T1—cut
题型:构造满足一定贡献的解。
Sam说是“Derandomization(去随机化)”?
通过分析,随机情况下割的大小的期望恰是1/2 m—虽然到这就可以随机nian过去了;
然而,我们希望“加以干预”—去随机化。
即我们当前要确定一个点的颜色时,可以考虑能否通过什么方式,使得之后选择的期望更优——
则有其法:若与该点相连的有色点中,黑色更多,则染白色——新增的贡献边不比放弃的边少!
考场时不太注意如何利用题目只需1/2 m 的特殊要求,便只交上暴力(随机意外AC。。)
T2—busy
题型:求排名L到R的 区间的贡献 f 。
经部分分(L=R)提示,这题大概有直接求某一排名区间的方法—二分 f 判断排名。
要求多个呢?像这种R-L+1很小的题目,一般是“由一推二”。则发现,若二分出L处与R处值,L、R之间的 f 范围也就知道了,然后可以 以 与判断排名类似的方式 直接找出符合条件的解—复杂度保证。
T3—palindrome
题型:字符串区间查询最长回文子串。无修改。
1.用马拉车直接找出回文串,再对是否超出边界讨论->RMQ问题(排序带个log)—没时间实现了。。。
2.二分长度,对不超过询问区间的位置用ST表查。
T4—night
题型:列式子后用 生成函数+多项式技巧 优化。
式子:
f
1
=
1
f
n
=
∑
i
=
1
n
−
1
f
i
∗
f
n
−
i
∗
g
i
\large f_1=1\\ \large f_n=\sum_{i=1}^{n-1}f_i*f_{n-i}*g_i
f1=1fn=i=1∑n−1fi∗fn−i∗gi
其中
∣
{
g
i
∣
g
i
≠
A
}
∣
≤
10
|\lbrace g_i| g_i\neq A\rbrace |\leq 10
∣{gi∣gi=A}∣≤10 。
容易想到把
g
i
≠
A
g_i\neq A
gi=A的项分离:
f
n
=
A
⋅
∑
i
=
1
n
−
1
f
i
⋅
f
n
−
i
+
∑
i
=
1
k
f
s
i
⋅
f
n
−
s
i
⋅
(
g
i
−
A
)
\large f_n=A\cdot\sum_{i=1}^{n-1}f_i\cdot f_{n-i} +\sum_{i=1}^{k}f_{s_i}\cdot f_{n-s_i}\cdot (g_i-A)
fn=A⋅i=1∑n−1fi⋅fn−i+i=1∑kfsi⋅fn−si⋅(gi−A)
设:
F
(
x
)
=
∑
f
i
⋅
x
i
v
i
=
g
i
−
A
P
(
x
)
=
∑
i
=
1
k
v
i
⋅
f
s
i
⋅
x
s
i
\large F(x)=\sum f_i\cdot x^i\\ \large v_i=g_i-A\\ \large P(x)=\sum_{i=1}^k v_i\cdot f_{s_i}\cdot x^{s_i}
F(x)=∑fi⋅xivi=gi−AP(x)=i=1∑kvi⋅fsi⋅xsi
有:
F
(
x
)
=
A
⋅
F
2
(
x
)
+
P
(
x
)
⋅
F
(
x
)
+
x
\large F(x)=A\cdot F^2(x)+P(x)\cdot F(x) +x
F(x)=A⋅F2(x)+P(x)⋅F(x)+x
进一步:
F
(
x
)
=
1
−
P
(
x
)
−
(
1
−
P
(
x
)
)
2
−
4
A
⋅
x
2
A
\large F(x)=\frac{1-P(x)-\sqrt{(1-P(x))^2-4A\cdot x}}{2A}
F(x)=2A1−P(x)−(1−P(x))2−4A⋅x
正负号取-,因为要消去常数项
问题在于求根号得到什么式子(设ta):
H
2
(
x
)
=
G
(
x
)
=
(
1
−
P
(
x
)
)
2
−
4
A
⋅
x
\large H^2(x)=G(x)=(1-P(x))^2-4A\cdot x
H2(x)=G(x)=(1−P(x))2−4A⋅x
Lemma
若 G ( x ) = F k ( x ) G(x)=F^k(x) G(x)=Fk(x) ,有 F ( x ) ⋅ G ′ ( x ) = k ⋅ F ′ ( x ) ⋅ G ( x ) F(x)\cdot G'(x)=k\cdot F'(x)\cdot G(x) F(x)⋅G′(x)=k⋅F′(x)⋅G(x)
对G(x)求导可证:
G ′ ( x 0 ) = lim x → x 0 F k ( x ) − F k ( x 0 ) x − x 0 = F k ( x ) − F k ( x 0 ) F ( x ) − F ( x 0 ) ⋅ F ( x ) − F ( x 0 ) x − x 0 = k ⋅ F k − 1 ( x 0 ) ⋅ F ′ ( x 0 ) ⇒ F ( x ) ⋅ G ′ ( x ) = k ⋅ F ′ ( x ) ⋅ G ( x ) \large G'(x_0)=\lim_{x\rightarrow x_0} \frac{F^k(x)-F^k(x_0)}{x-x_0}\\ =\frac{F^k(x)-F^k(x_0)}{F(x)-F(x_0)}\cdot\frac{F(x)-F(x_0)}{x-x_0}\\ =k\cdot F^{k-1}(x_0)\cdot F'(x_0)\\ \Rightarrow F(x)\cdot G'(x)=k\cdot F'(x)\cdot G(x) G′(x0)=x→x0limx−x0Fk(x)−Fk(x0)=F(x)−F(x0)Fk(x)−Fk(x0)⋅x−x0F(x)−F(x0)=k⋅Fk−1(x0)⋅F′(x0)⇒F(x)⋅G′(x)=k⋅F′(x)⋅G(x)
此式对多项式幂有很大用处(从低到高递推)。
由于此题的P(x)与F(x)的项相关,但每项又只与F(x)中较低次项的值有关,因此可以边递推F边“完善”P(阴间)。
因为相乘时 将int常量前置 爆了,调试好久。。
Day2
两小时拿分,两小时摸鱼。270。
T1—game
题型:简单期望----线性状态上一定概率向前后移动,问到终点步数期望。根据其必经状态转移——f_i=(f_i*A+B)/C。
T2—island
题型:模型转化+区间加减查i之前最靠近i的0(没有负数值)。
复杂的讨论都可以变成,求解由 [ a [ i ] , i ] [a[i],i] [a[i],i] (i能到的区域)的覆盖的连续区间的左侧第一个0。
维护方式可以是 记区间最小值+区间最靠右最小值,也可以只是区间最小值。
两者实现区别不大,前者的方式可以在区间查询时提前退出,实际的用时较短。
T3—copy
题型:简单字符串以及简单dp
题意:两种构串方式,求构串代价。一种已常数C代价,将结尾作为回文中心 在右复制一段 右半串;另一种加一个小写字符,每种字符有一个代价。
构串方式就很适合manacher啊。
出题人表示尴尬,有了加强版:第一种方式的代价改成复制串的长度的平方。
出题人:你还给我上马拉车(+动态凸包)?乖乖给我用正解(回文树上dp)。
…(待续)
T4—heap
题型:对数据结构 堆 的下滤排序过程中 元素位置变化的询问( 1 0 5 10^5 105级别次)。对序列( 1 0 5 10^5 105级别个元素)的某些区间求解。
part 1:
众所周知,从后往前对元素下滤调整的复杂度是O(n)的!
与从前往后上滤有什么区别???看:(
k
=
l
o
g
2
n
k=log_2n
k=log2n)
A
1
=
∑
i
=
0
k
−
1
2
i
⋅
i
=
O
(
n
log
n
)
A
2
=
∑
i
=
0
k
−
1
2
i
⋅
(
k
−
1
−
i
)
=
n
∑
i
=
0
k
−
1
2
i
−
k
⋅
(
k
−
1
−
i
)
A
3
=
∑
i
=
0
k
−
1
2
i
−
k
⋅
(
k
−
1
−
i
)
=
1
4
+
2
8
+
3
16
+
4
32
+
.
.
.
=
1
2
⋅
(
1
2
+
1
4
+
1
8
+
.
.
.
)
+
1
2
⋅
(
1
4
+
2
8
+
3
16
+
.
.
.
)
=
1
2
+
1
2
⋅
A
3
⇒
A
3
=
1
,
A
2
=
O
(
n
)
\space \large A_1=\sum_{i=0}^{k-1}2^i\cdot i =O(n\log n)\\ \space \large A_2=\sum_{i=0}^{k-1}2^i\cdot (k-1-i)\\ \large =n\sum_{i=0}^{k-1}2^{i-k}\cdot (k-1-i)\\ \large A_3=\sum_{i=0}^{k-1}2^{i-k}\cdot (k-1-i)\\ \large =\frac{1}{4}+\frac{2}{8}+\frac{3}{16}+\frac{4}{32}+...\\ \large =\frac{1}{2}\cdot(\frac{1}{2}+\frac{1}{4}+\frac{1}{8}+...)\\ \large +\frac{1}{2}\cdot (\frac{1}{4}+\frac{2}{8}+\frac{3}{16}+...)\\ \large =\frac{1}{2}+\frac{1}{2}\cdot A_3\\ \large \Rightarrow A_3=1,A2=O(n)
A1=i=0∑k−12i⋅i=O(nlogn) A2=i=0∑k−12i⋅(k−1−i)=ni=0∑k−12i−k⋅(k−1−i)A3=i=0∑k−12i−k⋅(k−1−i)=41+82+163+324+...=21⋅(21+41+81+...)+21⋅(41+82+163+...)=21+21⋅A3⇒A3=1,A2=O(n)
这并不是本题的重点。
Part 2:
发现下滤过程十分复杂:“往下走一会不知哪里就忽然停下了”
但直接从结果考虑,最小的元素一定会到根;次小的似乎可以根据初始位置推断…
于是考虑最小元素如何变化—它会一直走到根,而路径上的点下移 且相对位置不变(?)。这里只考虑了最小元素在整个过程中的移动,以及部分元素单次的移动,如果按照这种规则移动,是否会与一次性下滤(多次移动)的结果不同呢?可以发现由于移动顺序的特殊性,两者的结果完全相同。
于是我们有了思路:找到子树最小值->移动到子树根->进入需查询点的子树继续这个过程。
区间里的数太多,无法都遍历一遍,因此只有变动的位置可以“操作”,其余位置需“特殊查询”—发现堆上 同层元素 在原序列的 一段区间。于是找最小值时,使用log次(每层一次)区间查询(无修改,ST表 O(1) 查)。然而跳上去的元素(log 个)不该查询,就记录其位置并将询问区间分开。而此时仍有未查询到的元素—从上往下移动进子树的,由于其个数不超过log个,可以从子树根位置开始搜移动到该位置的元素,直到该元素已在子树中。
需要记录每个元素的位置,每个移动过的位置的元素为何 等信息。
实现较复杂,想好再打!
还未调试出来的代码:
Code
#include<cstdio>
#define N 100005
#define ll long long
#define mo 998244353
using namespace std;
inline int read()
{
int x=0;char ch=getchar();
while (ch<'0'||ch>'9')ch=getchar();
while (ch>='0'&&ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
int n,Q;
int st[17][N],lg[N];
const int w[17]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536};
#define min(a,b) (a<b?a:b)
inline int get(int x,int y)
{
if (x>y)return n;
int l=lg[y-x+1];
return min(st[l][y],st[l][x+w[l]-1]);
}
int a[N],pa[N],b[N],pb[N];
int lis[400],tot;
#define c(x) (b[x]?b[x]:a[x])
#define pc(v) (pb[v]?pb[v]:pa[v])
inline void set(int p,int x)
{
if (!b[p])lis[++tot]=p;
pb[b[p]=x]=p;
}
int ty,l,r,x,y,z;
inline void find(int i,int rt)
{
if (i+l-1>r||!b[i+l-1])return;
if (pa[b[i+l-1]]<rt)
{
if (z>b[i+l-1])z=b[i+l-1];
find(i*2,rt);
find(i*2+1,rt);
}
}
int dir[N];
int list[20],tl;
const int hd=1;
#define swap(x,y) x^=y^=x^=y
inline void lift(int rt,bool ty)
{
z=n;find(rt-l+1,rt);
// find
for (int L=rt-l+1,R=rt-l+1,i=hd;;L<<=1,R=(R<<1)+1)
{
if (R+l-1>r)R=r-l+1;
for (int j=L;j<=R;)
{
while (i<=tl&&list[i]<j+l-1)++i;
if (i<=tl&&list[i]<=R+l-1)
{
z=min(z,get(j+l-1,list[i]-1));
j=list[i]-l+2;
}else
{
z=min(z,get(j+l-1,R+l-1));
break;
}
}
if (R==r-l+1)break;
}
//end
// add z to list
list[++tl]=pa[z];
for (int i=tl;i>hd&&list[i]<list[i-1];--i)
swap(list[i],list[i-1]);
// rec b
if (ty)
{
// rec dir
for (int i=pc(z)-l+1;i!=rt-l+1;i>>=1)
{
if (c((i>>1)+l-1)==x)dir[(i>>1)+l-1]=i+l-1;
set(i+l-1,c((i>>1)+l-1));
}
set(rt,z);
}else
{
for (int i=pc(z)-l+1;i!=rt-l+1;i>>=1)
set(i+l-1,c((i>>1)+l-1));
set(rt,z);
}
}
inline void dfs(int rt)
{
if (rt==l)
{
lift(rt,0);
return;
}
dfs(((rt-l+1)>>1)+l-1);
lift(rt,0);
if (rt==x+l-1)
printf("%d\n",c(x+l-1));
}
inline void dfs2(int rt)
{
lift(rt,1);
if (c(rt)==x)
{
printf("%d\n",rt-l+1);
return;
}dfs2(dir[rt]);
}
int main()
{
freopen("heap.in","r",stdin);
freopen("heap.out","w",stdout);
n=read();Q=read();
for (int i=1;i<=n;++i)
{
st[0][i]=a[i]=read();
pa[a[i]]=i;
if (i>1)
lg[i]=lg[i>>1]+1;
for (int j=0;j<lg[i];++j)
st[j+1][i]=min(st[j][i],st[j][i-w[j]]);
}
while (Q--)
{
ty=read();
l=read();
r=read();
x=read();
y=n;
// hd=1;
tl=0;
if (ty==1)//pos -> val
{
dfs(x+l-1);
}else //val -> pos
{
for (int i=pa[x]-l+1;i!=1;i>>=1)dir[(i>>1)+l-1]=i+l-1;
dfs2(l);
for (int i=l,j;i;dir[j]=0)i=dir[j=i];
}
while (tot)
{
pb[b[lis[tot]]]=0;
b[lis[tot]]=0;
--tot;
}
}
}
Day3
难度暴涨???60。
你说这(普及)+(普及)+(省选+)= (提高)???
T1:
…(待续)