用户工具

站点工具


2020-2021:teams:die_java:front_page_summertrain13

这是本文档旧的修订版!


2020牛客暑期多校训练营(第九场)

训练结果

  • 时间:2020-08-17 13:00~18:00
  • rank:61/951
  • 完成情况:5/6/11

I.Just Skip The Problem

题意

题解

代码

代码

 

J.Just Skip The Problem

题意

求 $n$ 的阶乘,水

K.Keen On Everything But Triangle

题意

给出一排长度不同的木棒,每次询问一个区间,求这个区间木棒能构成周长最长的三角形

题解

对于一部分木棒,一定是优先选最大的三个尝试组合

如果三个木棒不合法,那么最小的和最大的差别一定减半,所以可以暴力$O(logn)$枚举

那么枚举最大的是第几大,用线段树查询即可

代码

代码

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 100005,maxm = 10000005,INF = 0x3f3f3f3f;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
	return flag ? out : -out;
}
int rt[maxn],sum[maxm],ls[maxm],rs[maxm],pos,siz,n,Q;
LL a[maxn],b[maxn],tot;
void add(int& u,int v,int l,int r){
	u = ++siz; ls[u] = ls[v]; rs[u] = rs[v]; sum[u] = sum[v];
	if (l == r){sum[u]++;return;}
	int mid = (l + r) >> 1;
	if (mid >= pos) add(ls[u],ls[v],l,mid);
	else add(rs[u],rs[v],mid + 1,r);
	sum[u] = sum[ls[u]] + sum[rs[u]];
}
LL ans,L,R;
int kth(int u,int v,int l,int r,int k){
	if (l == r) return l;
	int mid = (l + r) >> 1;
	if (sum[rs[u]] - sum[rs[v]] >= k) return kth(rs[u],rs[v],mid + 1,r,k);
	return kth(ls[u],ls[v],l,mid,k - sum[rs[u]] + sum[rs[v]]);
}
void work(){
	while (Q--){
		L = read() - 1; R = read(); ans = -1;
		LL K = 1,t,tt,ttt;
		while (K + 2 <= R - L){
			t = b[kth(rt[R],rt[L],1,tot,K)];
			tt = b[kth(rt[R],rt[L],1,tot,K + 1)];
			ttt = b[kth(rt[R],rt[L],1,tot,K + 2)];
			if (t < tt + ttt) {ans = t + tt + ttt; break;}
			K++;
		}
		printf("%lld\n",ans);
	}
}
int main(){
	while (scanf("%d%d",&n,&Q)==2){
		siz = 0;
		REP(i,n) b[i] = a[i] = read();
		sort(b + 1,b + 1 + n); tot = 1;
		for (int i = 2; i <= n; i++) if (b[i] != b[tot]) b[++tot] = b[i];
		REP(i,n) a[i] = lower_bound(b + 1,b + 1 + tot,a[i]) - b;
		REP(i,n) pos = a[i],add(rt[i],rt[i - 1],1,tot);
		work();
	}
	return 0;
}

L.Longest Subarray

题意

一个序列每个位置有一种颜色,找到一个最长的子区间,使得每种颜色要么出现过超过$K$次,要么出现过$0$次

题解

从后往前枚举位置作为子区间的开端,每种颜色有两种状态:

1、数量不足,不能被包含,那么这些位置都被禁了,要选一个最大的子区间,那么右端点一定在最左边被禁的地方

2、当前数量足够$K$个,记录一下如果要包含这种颜色,最少要包含到哪个位置

那么每次只需要在线段树上找当前区间最大值有没有超过设定的右端点即可

代码

代码

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 0x3f3f3f3f;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
	return flag ? out : -out;
}
int n,C,K,ans,A[maxn];
vector<int> pos[maxn];
int sc[maxn],top;
int mx[4 * maxn],L,R;
void modify(int u,int l,int r,int v){
	if (l == r){mx[u] = v; return;}
	int mid = (l + r) >> 1;
	if (mid >= L) modify(ls,l,mid,v);
	else modify(rs,mid + 1,r,v);
	mx[u] = max(mx[ls],mx[rs]);
}
int query(int u,int l,int r){
	if (l >= L && r <= R) return mx[u];
	int mid = (l + r) >> 1;
	if (mid >= R) return query(ls,l,mid);
	else if (mid < L) return query(rs,mid + 1,r);
	return max(query(ls,l,mid),query(rs,mid + 1,r));
}
void build(int u,int l,int r){
	if (l == r){mx[u] = 0; return;}
	int mid = (l + r) >> 1;
	build(ls,l,mid);
	build(rs,mid + 1,r);
	mx[u] = 0;
}
void work(){
	build(1,1,n); ans = 0; top = 0;
	for (int i = n; i; i--){
		int u = A[i];
		pos[u].push_back(i);
		sc[++top] = u;
		while (pos[sc[top]].size() >= K) top--;
		if (pos[u].size() >= K) {
			if (pos[u].size() > K){
				L = pos[u][pos[u].size() - 2];
				modify(1,1,n,0);
			}
			L = i;
			modify(1,1,n,pos[u][pos[u].size() - K]);
		}
		L = i; R = top ? pos[sc[top]][pos[sc[top]].size() - 1] - 1 : n;
		if (L <= R){
			if (query(1,1,n) <= R) ans = max(ans,R - L + 1);
		}
	}
	REP(i,C) pos[i].clear();
	printf("%d\n",ans);
}
int main(){
	while (~scanf("%d%d%d",&n,&C,&K)){
		REP(i,n) A[i] = read();
		work();
	}
	return 0;
}

训练实况

训练总结

wxg:

hxm:比较遗憾B最后差一点没写出

fyh:

2020-2021/teams/die_java/front_page_summertrain13.1598000686.txt.gz · 最后更改: 2020/08/21 17:04 由 wxg