GDKOI2021总结

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=1n1fifnigi
其中 ∣ { g i ∣ g i ≠ A } ∣ ≤ 10 |\lbrace g_i| g_i\neq A\rbrace |\leq 10 {gigi=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=Ai=1n1fifni+i=1kfsifnsi(giA)
设:
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)=fixivi=giAP(x)=i=1kvifsixsi
有:
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)=AF2(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)=2A1P(x)(1P(x))24Ax
正负号取-,因为要消去常数项

问题在于求根号得到什么式子(设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)=(1P(x))24Ax

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)=kF(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)=xx0limxx0Fk(x)Fk(x0)=F(x)F(x0)Fk(x)Fk(x0)xx0F(x)F(x0)=kFk1(x0)F(x0)F(x)G(x)=kF(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=0k12ii=O(nlogn) A2=i=0k12i(k1i)=ni=0k12ik(k1i)A3=i=0k12ik(k1i)=41+82+163+324+...=21(21+41+81+...)+21(41+82+163+...)=21+21A3A3=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:

…(待续)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值