【学习笔记】2021.10.6 - 清北学堂模拟赛

T1 区间第k大

题目内容

  • 给定一个 \(1\sim n\) 的排列 \(\{p_i\}\) 以及整数 \(k\)

  • 对于每个 \(i \in [1,n]\),你需要求出该排列中有多少个区间 \([l,r]\) 的第 \(k\) 大恰好是 \(p_i\)

  • 输入一行 \(n\) 个整数,第 \(i\) 个整数表示有多少个区间以 \(p_i\) 作为第 \(k\) 大。

  • 输出一行 \(n\) 个整数,第 \(i\) 个整数表示有多少个区间以 \(p_i\) 作为第 \(k\) 大。

Subtask1

\(n \leq 1000\)

思路

  • 建一棵主席树,干就完了

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long ll;
const int MAXN(300233);
struct poi{
	int ls,rs,sum,lt;
}tree[MAXN<<5];
int cnt,p[MAXN],n,kkksc03,rt[MAXN],ans[MAXN],cha[MAXN];
inline int R(){
	int x=0;char c='c';
	while(c>'9'||c<'0') c=getchar();
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return x;
}
inline void BUILD(int OLD,int &NOW,int l,int r,int num){
	NOW=++cnt;
	tree[NOW].ls=tree[OLD].ls;
	tree[NOW].rs=tree[OLD].rs;
	tree[NOW].sum=tree[OLD].sum+1;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(num<=mid) BUILD(tree[OLD].ls,tree[NOW].ls,l,mid,num);
	else BUILD(tree[OLD].rs,tree[NOW].rs,mid+1,r,num);
	return;
}
inline int QUERY(int L,int R,int l,int r,int k){
	if(l==r) return l;
	int lsum=tree[tree[R].ls].sum-tree[tree[L].ls].sum;
//	printf("l %d r %d mid %d k %d lsum %d Llssum %d Rlssum %d\n",l,r,(l+r)>>1,k,lsum,tree[tree[L].ls].sum,tree[tree[R].ls].sum);
	int mid=(l+r)>>1;
	if(k<=lsum) return QUERY(tree[L].ls,tree[R].ls,l,mid,k);
	else return QUERY(tree[L].rs,tree[R].rs,mid+1,r,k-lsum);
}
int main(){
//	freopen("ex_sequence3.in","r",stdin);
//	freopen("my.txt","w",stdout); 
	n=R();kkksc03=R();
	for(register int i=1;i<=n;++i) p[i]=R(),cha[p[i]]=i;
	for(register int i=1;i<=n;++i) BUILD(rt[i-1],rt[i],1,n,p[i]);
	for(register int i=1;i<=n-kkksc03+1;++i)
		for(register int j=i+kkksc03-1;j<=n;++j)
//		printf("QUE %d ~ %d:\n",i,j),
			ans[cha[QUERY(rt[i-1],rt[j],1,n,j-i-kkksc03+2)]]++;
	for(register int i=1;i<=n;++i) printf("%d ",ans[i]);
	printf("\n");
	return 0;
}
//打五把CS:GO! 

期望得分 50pts

正解

思路

  • 由于k固定,主席树真是太亏了!

  • 考虑到只关心大小关系,我们可以预处理一个01数组,把比某位置大的赋值为1,反之为0,只需向前向后暴力拓展k个,然后计算即可。

  • 复杂度 \(O(nk)\)

T2 染色

题目内容

  • \(n\) 个球排成一排,有 \(c\) 种颜色。这些球中有 \(m\) 个球已经染上了某种颜色。

  • 你可以选择某个未被染色的球 \(i\),以及与它相邻且已被染色的球 \(j\),将球 \(i\) 染成球 \(j\) 的颜色。

  • 当所有球都被涂上颜色后,设第 \(i\) 种颜色的球有 \(t_i\) 个。定义长为 \(c\) 的序列 \(\{a_i\}\) 满足 \(a_i= (t_i,i)\),其中括号表示有序对。

  • 请求出对于所有可能的染色方案,序列 \(a\) 从大到小排序后字典序最大是多少。

  • 两个有序对比较大小的方法为先比较第一个元素的大小,若相同再比较第二个元素的大小。

  • 注意:\(c\) 种颜色不一定会全部出现在已经染好色的球中。

  • 输入第一行三个整数 \(n,m,c\),分别表示球数,已染色的球数和颜色种数。

  • 接下来 \(m\) 行,第 \(i\) 行两个整数 \(x_i,b_i\) 分别表示已染色球的位置和染的颜色。保证 \(x_i\) 严格递增。

  • 输出输出 \(c\) 行,第 \(i\) 行两个正整数 \(x,y\) 表示答案序列(序列 \(a\) 从大到小排序后)的第 \(i\) 个有序对 \((x,y)\)

Subtask1

\(n,m,c \leq 15\)

思路

  • 贪心,每次扫一遍整个序列,按照第一关键字找到颜色最多的染色,第一关键字相同根据第二关键字不同进行染色。

代码

  • 无QWQ

期望得分 20pts

Subtask3

\(m \leq 17\)

思路

  • 枚举使用已经染色的球的所有方案,然后再进行处理即可

  • 复杂度 \(O(2^m \times 17)\)

代码

  • 无QWQ

期望得分 40pts

正解

思路

  • 对于每个染了色的球建点,向未染色的段连边,边权为段的长度,最后求最大值和删边,考虑用大根堆,更改操作不用管,把新点扔到大根堆里即可,复杂度 \(O(c+m\log n)\)

代码

  • 无QWQ

期望得分 100pts

T3 博弈论

题目内容

  • 小T刚刚学习了博弈论的相关内容,他对 \(\rm mex\) 函数很感兴趣,于是想出了如下问题。

  • 给定 \(n\) 个结点的树,结点编号为 \(1\sim n\),第 \(i\) 个结点上有点权 \(a_i\)。保证 \(\{a_i\}\) 为一个 \(0\sim n-1\) 的排列。

  • 你需要对于每个 \(c\in [0,n-1]\),求出将每个点的点权 \(a_i\) 变为 \((a_i+c)\bmod n\),之后求出树上所有链的 \(\rm mex\) 值的最大值。

  • 一条 \(u\)\(v\) 的链的 \(\rm mex\) 值定义为这条链的点权构成的集合中,没有出现过的最小自然数(自然数包括0)。

  • 注意:询问之间独立,也即每个询问的修改仅对当前询问有效。

  • 输入:

  • 第一行一个整数 \(n\),表示树的大小。

  • 第二行 \(n\) 个整数 \(a_i\),表示点权。

  • 接下来 \(n-1\) 行,每行两个整数 \(u_i,v_i\),表示一条树边 \((u_i,v_i)\)

  • 输出一行 \(n\) 个整数,第 \(i\) 个整数表示 \(c=i-1\) 时的答案。

正解

思路

  • 先考虑 \(c=0\) 时的答案,此时要将 \(1 \sim n\) 依次加入直到不能形成链,使得mex最大。

  • 维护链的起点 S 和终点 T ,若新加入的点正好在 S 或 T 上就直接把它挂上去。

  • 若不是……

  • 一会再说,先说一个重要的知识:

inline int LCA_OF_THREE(int x,int y,int z){
	return lca(x,y)^lca(x,z)^lca(y,z);
}
//求三点LCA
  • 多余的部分全都抑或抵消掉了,所以这是正确的。

  • 后面的听不会了,人傻了,看Minus神仙的博客罢。

  • 复杂度 \(O(n\log n)\)

代码

  • 无QWQ

正解(超级加倍)

  • 先讲一个技巧:双栈模拟队列。

  • 就是让两个栈的栈底拼在一起,右栈往右移动时让右栈入栈,左栈弹栈,弹空了就把交界点的位置改变,防止GG。

  • 剩下的仍然不会,看Minus神仙的博客罢。

T4 错排问题

题目内容

  • 一个 \(1\sim n\) 的排列 \(p\) 被称为错排,当且仅当对于每个 \(i\) ,有 \(p_i \not= i\)

  • 给定整数 \(n,m\),你需要求出对于每个 \(k\in[0,m]\),满足 \(\sum_{i=1}^n|p_i-i|=k\) 且长为 \(n\) 的错排 \(p\) 有多少个。

  • 由于答案很大,你只需要输出答案对 \(998244353\) 取模的结果。

  • 输入一行两个整数 \(n,m\),表示错排长度和 \(k\) 的取值范围。

  • 输出一行 \(m+1\) 个整数,第 \(i\) 个整数表示 \(k=i-1\) 时的答案对 \(998244353\) 取模的结果。

Subtask1

\(n \leq 10\)

思路

  • 打表出省一。

代码

  • 无QWQ

Subtask4

  • 全程伞兵,弃疗了……
posted @ 2021-10-06 13:41  Binaries  阅读(229)  评论(2编辑  收藏  举报
浏览器标题切换
浏览器标题切换end