230715校内赛

T1 串

背景

形貌昳丽的西克是風子国王嫡系军队的 general, 同时也兼任風子王国驻绿鸟国的外交官。

西克喜欢在蕉含流群里与其它王国的使者蕉含流, 但前段时间由于说怪话被来自绿鸟国意识形态 不完全的国王驱含逐出境。

西克非常愤怒, 想要说出一句最怪的话, 但他却忙于敢览求社的训练。

于是, 他找到了你, 无上尼特, 想让你帮助解决他的问题。

题目描述

在風子王国, 一句话由 n 个词组成, 其中恰好有 k 个词是怪的, 其它的词都不是怪的。

众所周知, 负负得正, 我们定义一句话的一个区间是怪的, 当且仅当其中含有奇数个怪词。

请构造一句符合条件的话, 使得其中怪的区间数量最多。

输入格式

从文件 string.in 中读入数据。

一行两个整数 n,k

输出格式

输出到文件 string.out 中。

第一行一个整数 ans, 表示至多可以有的怪的区间个数。

第二行一个长度为 n 的 01 串, 表示构造方案, 若一个单词是怪的, 输出 1 , 否则输出 0 , 字符 间用空格隔开。

本题使用自定义校验器检验你的答案是否正确, 因此若有多种满足条件的方案, 你只需要输出任 意一种。

样例

输入数据 1

7 2

输出数据 1

16 
0 1 0 0 0 1 0

怪的区间有 [1, 2], [1, 3], [1, 4], [1, 5], [2, 2], [2, 3], [2, 4], [2, 5], [3, 6], [3, 7], [4, 6], [4, 7], [5, 6], [5, 7], [6, 6], [6, 7] 共 16 个。

数据规模与约定

对于所有测试点:1n1050kn

每个测试点的具体限制见下表:

测试点 n k
1∼2 10 ≤n
3∼5 103 同上
6∼7 105 1
8 同上 2
9∼10 n n

题解

打表题,正常看挺难看出它的规律,打表则很容易计算出来

是我不会推导

有人忘了开longlong,还没特判

大概看了一下正常思路代码我就不写了

先特判 k=0 的情况。

将数组做前缀和, 令前缀和数组中 1 的个数为 X,0 的个数为 Y, 则答案为 X×Y, 由于X+Y=n+1, 所以我们只需要让 X,Y 尽量接近, 一种简单的做法是先在最前方放 k1 个 1 , 再在后面的位置中选择最优 的位置放一个 1 , 可以发现, 这样构造一定能够做到 X×Y 取到最大, 时间复杂度 O(n),

#include<bits/stdc++.h>
using namespace std;
int n,k,a[100010];
long long ans;
int main(){
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	scanf("%d%d",&n,&k);
	if(k==0){
		puts("0");
		for(int i = 1;i<=n;i++)	
			printf("0 ");
		return 0;
	}
	ans = (long long)((n/2)+1)*(long long)(n/2);
	if(n%2==1) ans+=(long long)(n/2)+1;
	printf("%lld\n",ans);
	for(int i = n;i>=n-k+2;i--) a[i] = 1;
	a[(n-k)/2+1] = 1;
	for(int i = 1;i<=n;i++)
		printf("%d ",a[i]);
	return 0;
}

背景

吉娜是一名艺术家, 一名表演艺术家 (performance artist)。

此时正值風子王国建国 114514 周年, 風子国王抵德请来艺术家吉娜设计游行的道路。

吉娜非常重占视这份工作, 但却在喝水的时候被巡逻的抵德训占斥工作不认真, 于是剥占夺了吉 娜的设计权利, 将吉娜贬含为了负责计算道路的信息的计算机。

吉娜心想: “为什么设计的时候不能喝水? ?? 我听歌都可以设计好。”

但终是敢怒占不敢言, 不幸的是, 计算量实在太大, 吉娜怕黑, 必须赶在天黑占之前做完工作。 于是他请来了你, 伟大尼特, 帮助它解决这个问题。

题目描述

给定一个长度为 n 的颜色序列 c 。

再给出 m 个区间, 第 i 个区间为 [li,ri] 保证任何两个区间都是不相交或包含的关系。

在接下来的 q 个单位时间内, 第 i 个时间会给定 x,y, 表示将 cx 变为 y

请对于每一个区间求出, 最早的其中所有颜色都互不相同的时间。

输入格式

从文件 artist.in 中读入数据。

第一行三个正整数 n,m,q

接下来一行 n 个整数, 第 i 个数表示第 i 个点的初始颜色 ci

接下来 m 行, 每行两个整数 li,ri

接下来 q 行, 每行两个整数 x,y, 表示一次修改。

输出格式

输出到文件 artist.out 中。

Li 表示第 i 个区间之中最早的所有颜色互不相同的时间, 若在修改前就已经满足条件, 则 Li=0, 若不存在这样的时间, 则令 Li=m+i

请输出 i=1mLi, 其中 表示二进制下的按位异或。

样例

输入数据 1

6 6 5 
1 2 1 2 1 2 
1 6 
5 5 
4 5 
3 5
2 5 
1 5 
5 2 
4 3 
2 1 
3 4 
1 5

输出数据 1

4

【样例解释 1】

Li 依次为 7,0,0,2,4,5 。

数据规模与约定

对于所有数据, 满足 1n,m,q5×105,1lirin,1ci,yn, 保证任何两个区间都是 不相交或包含的关系,保证不存在两个完全相同的区间。

题解

发现所有区间不相交也不包含, 可以看作一个树形的关系, 一个区间的父亲必须在这个区间之后满足要求, 同时, 所有的叶子节点的区间互不相交, 相当于每个点只会在当前的一个区间中, 每次修改之后查询这个区 间是否合法即可。

查询一个区间是否合法有两种方式:

  1. 建出树, 相当于一个单点修改, 子树数颜色, 使用 dfsdfs 序, set, 树状数组可以做到 O(logn)

  2. 在原数轴上维护 lsti 表示 i 之前第一个颜色与 i 相同的点, 则一个区间内部颜色互不相同等价于 min{lsti,lir}, 使用 set 和线段树维护可以做到 O(logn)

    时间复杂度 O(n+(m+q)logn)

#include<bits/stdc++.h>
#define N 500010
#define mid ((l+r)>>1)
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
struct node{
	int x,y,id;
	bool operator<(const node &a)const{
		return x==a.x?y>a.y:x<a.x;
	}
}stk[N],p[N];
set<node>s;
set<node>::iterator it1;
set<int>st[N];
set<int>::iterator it;
int n,m,q,cnt,tim,X,Y,tp,lf[N],rg[N],rd[N],ans[N],c[N],h[N],ne[N],t[N<<2],lst[N],fa[N],pos[N],pre[N];
void add(int p,int l,int r){
	if(l==r){
		t[p] = Y;
		return ;
	}
	if(X<=mid) add(lc,l,mid);
	else add(rc,mid+1,r);
	t[p] = max(t[lc],t[rc]);
}
int ask(int p,int l,int r,int ql,int qr){
	if(ql<=l&&qr>=r) return t[p];
	int res = 0;
	if(ql<=mid) res = max(res,ask(lc,l,mid,ql,qr));
	if(qr>mid) res = max(res,ask(rc,mid+1,r,ql,qr));
	return res;
}
void build(int p,int l,int r){
	if(l==r){
		t[p] = lst[l];
		return ;
	}
	build(lc,l,mid);
	build(rc,mid+1,r);
	t[p] = max(t[lc],t[rc]);
}
void change(int x,int y){
	if(ne[x]){
		X = ne[x];
		Y = lst[x];
		add(1,1,n);
	}
	ne[lst[x]] = ne[x];
	lst[ne[x]] = lst[x];
	st[c[x]].erase(x);
	c[x] = y;
	int p = lst[x];
	it = st[y].upper_bound(x);
	lst[x] = ne[x] = 0;
	if(it!=st[y].end()){
		X = *it;
		ne[x] = X;
		Y = x;
		add(1,1,n);
	}
	if(it!=st[y].begin()){
		it--;
		lst[x] = *it;
	}
	st[y].insert(x);
	lst[ne[x]] = ne[lst[x]] = x;
	X = x;
	Y = lst[x];
	if(p^Y) add(1,1,n);
}
void check(int x){
	if(ask(1,1,n,lf[x],rg[x])<lf[x]){
		s.erase((node){lf[x],rg[x],x});
		ans[x] = tim;
		if(fa[x]&&(!(--rd[fa[x]]))){
			rd[fa[x]] = -1;
			s.insert(p[pos[fa[x]]]);
			check(fa[x]);
		}
	}
}
int main(){
	freopen("artist.in","r",stdin);
	freopen("artist.out","w",stdout);
	scanf("%d%d%d",&n,&m,&q);
	for(int i = 1;i<=n;i++)	
		scanf("%d",&c[i]);
	for(int i = 1;i<=m;i++){
		lst[i] = pre[c[i]];
		ne[pre[c[i]]] = i;
		pre[c[i]] = i;
		st[c[i]].insert(i);
	}
	build(1,1,n);
	for(int i = 1;i<=m;i++){
		scanf("%d%d",&p[i].x,&p[i].y) ;
		lf[i] = p[i].x;rg[i] = p[i].y;
		ans[i] = m+i;
		p[i].id = i;
	}
	sort(p+1,p+m+1);
	for(int i = 1;i<=m;i++){
		if(p[i].x==p[i].y||ask(1,1,n,p[i].x,p[i].y)<p[i].x){
			ans[p[i].id] = 0;
			rd[p[i].id] = -1;
			continue;
		}
		pos[p[i].id] = i;
		while(tp&&stk[tp].y<p[i].x) tp--;
		fa[p[i].id] = stk[tp].id;
		stk[++tp] = p[i];
		rd[fa[p[i].id]]++;
	}
	for(int i = 1;i<=m;i++){
		if(!rd[p[i].id])
			s.insert(p[i]);
	}
	for(int i = 1;i<=q;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		tim = i;
		change(x,y);
		it1 = s.upper_bound((node){x,0,0});
		if(it1!=s.begin()){
			it1--;
			check((*it1).id);
		}
	}
	int res = 0;
	for(int i = 1;i<=m;i++)
		res^=ans[i];
	printf("%d",res);
	return 0;
}

T3 黑白树(tree)

背景

一天, 風子国王抵德带着助手尼特以及西可和西克来到一片 dark 含森林探险, 在这里, 它们发 现了 n 个阿玮。

与此同时, 杰哥带着彬概也正好发现了这些阿玮。

与此同时, 抵德也发现了杰哥带着彬彬也正好发现了这些阿玮。

抵德说: “如果这些阿玮给你的话, 那么它们就不是我的了”。

杰哥说: “如果这些阿玮给你的话, 那么它们就不是我的了”。

两边吵得不可开蕉♂,这时,尼特发现,这些阿玮有些非常逊,有一些非常勇♂,于是经过调解, 抵德带走了所有逊的阿玮, 杰哥带走了所有勇含的阿玮。

同时, 尼特发现这 n 个阿玮之间仿佛产生了 n1 条联系, 构成了一棵树的关系。

题目描述

给定一棵 n 个点的树, 每一个结点都可以是黑色或白色, 每一条边的长度都为 1 。

定义两个点的距离为两个点最短路径上边的条数, 定义一棵树的价值, 为同色点距离的最大值。 请求出在所有情况下, 树的价值之和, 对 109+7 取模。

输入格式

从文件 tree.in 中读入数据。

第一行一个正整数 n

接下来 n1 行, 每行两个数 x,y, 表示树中的一条边。

输出格式

输出到文件 tree.out 中。

输出一行一个数, 表示你的答案, 对 109+7 取模。

样例

输入数据 1

2
1 2

输出数据 1

2

【样例解释 1】

若两个点颜色相同,同色点距离最大值为 1。

若两个点颜色不同,同色点距离最大值为 0。

输入数据 2

6 
1 2 
2 3 
3 4 
4 5 
3 6

输出数据 2

224

题解

#include<bits/stdc++.h>
#define N 1000010
#define mod 1000000007
using namespace std;
struct edge{
	int v,ne;
}e[N<<1];
int n,s,cnt,ans,pos,sum,h[N],dis[N],c[N],dis1[N],c1[N];
bool vis[N];
void add(int u,int v){
	e[++cnt].v = v;
	e[cnt].ne = h[u];
	h[u] = cnt;
}
int ksm(int x,int y){
	int ans = 1;
	while(y){
		if(y&1) ans = 1ll*ans*x%mod;
		x = 1ll*x*x%mod;
		y>>=1;
	}
	return ans;
}
void dfs(int u,int fa,int x){
	dis[u] = x;
	if(dis[u]>dis[pos]) pos = u;
	for(int i = h[u];i;i = e[i].ne){
		int v = e[i].v;
		if(v!=fa) dfs(v,u,x+1);
	}
}
int main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%lld",&n);
	for(int i = 1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);add(v,u);
	}
	dfs(1,1,0);
	int x = pos;
	pos = 0;
	dfs(x,x,0);
	for(int i = 1;i<=n;i++){
		if(dis[i]==dis[pos])
			sum++;
		c[dis[i]]++;
	}
	for(int i = 1;i<=n;i++){
		dis1[i] = dis[i];
		c1[i] = c[i];
	}
	x = pos;
	dfs(x,x,0);
	memset(c,0,sizeof(c));
	for(int i = 1;i<=n;i++){
		if(dis[i]==dis[pos])
			sum++;
		c[dis[i]]++;
	}
	for(int i = 1;i<=n;i++)
		vis[min(dis[i],dis1[i])] = true;
	int mx = dis[pos];
	sum = ksm(2,n);
	s = n+1;
	for(int i = mx;~i;i--){
		if(vis[i]){
			ans = (ans+1ll*sum*i%mod)%mod;
			printf("%d",ans);
			return 0;
		}
		s-=c[i];
		s-=c1[i];
		int tmp = ksm(2,s);
		ans = (ans+1ll*i*(sum-tmp+mod)%mod)%mod;
		sum = tmp;
	}
	return 0;
}

T4敢览求(rugby)

题目

题解

写不动了容我偷个懒

这道题根本不是给人写的吧

#include<bits/stdc++.h>
#define N 200010
using namespace std;
struct node{
	int x,y;
	bool operator <(const node A)const{
		return x==A.x?y<A.y:x<A.x;
	}
};
int n,K,ls[N],rs[N],a[N],b[N],f[N],cc,tot;
multiset<node>st[N];
multiset<node>::iterator it,it1,it2,it3,it4;
void find(multiset<node>&A,int x){
	it1 = A.upper_bound((node){x+1,-1});
}
bool ck(multiset<node>&A,multiset<node>&B){
	cc = 0;
	for(it = B.begin();it!=B.end();it++){
		find(A,(*it).x);
		if(it1!=A.begin()){
			it1--;
			if((*it1).y>=(*it).x) return 1;
			it1++;
		}
		if(it1!=A.end()&&(*it1).x<=(*it).y)return 1;
		tot++;
	}
	return 0;
}
void cg1(multiset<node>&A,multiset<node>&B){
	it2 = A.begin();
	cc = 0;
	for(it = B.begin();it!=B.end();it++){
		find(A,(*it).x);
		while(it2!=A.end()&&(*it2).y<(*it).x)it3=it2,++it2,A.erase(it3);
		if(it1!=A.begin()){
			it1--;
			int xx = -1;
			if((*it1).y>=(*it).x){
				xx = min((*it).y,(*it1).y); 
				A.insert((node){(*it).x,xx});
				A.erase(it1);
			}
			if(~xx&&(*it1).y!=xx) A.insert((node){xx+1,(*it1).y});
		}
		find(A,(*it).y);
		if(it1!=A.begin()){
			it1--;
			int xx = -1;
			if((*it1).x<=(*it).y){
				xx = min((*it).y,(*it1).y); 
				A.insert((node){(*it).x,xx});
			}
			if(~xx&&(*it1).y!=xx) A.insert((node){xx+1,(*it1).y});
			A.erase(it1);
		}
		it2 = A.upper_bound((node){(*it).y+1,-1});
		tot++;
	}
	while(it2!=A.end()){
		it3 = it2;
		it2++;
		A.erase(it3);
	}
}
void cg2(multiset<node>&A,multiset<node>&B){
	for(it = B.begin();it!=B.end();it++){
		int l = (*it).x,r = (*it).y;
		find(A,l);
		if(it1!=A.begin()){
			it1--;
			l = max(l,(*it1).y+1);
			it1++;
		}
		while(it1!=A.end()&&(*it1).y<=r){
			it2 = it1;
			it1++;
			A.erase(it2);
		}
		if(it1!=A.end()) r = min(r,(*it1).x-1);
		if(l<=r) A.insert((node){l,r});
		tot++;
	}
}
void dfs(int x){
	if(!ls[x]) swap(ls[x],rs[x]);
	if(ls[x]) dfs(ls[x]);
	if(rs[x]) dfs(rs[x]);
	if(a[x]>=b[x]){
		st[x].insert((node){0,K-a[x]-1});
		if(b[x]) st[x].insert((node){K-b[x],K-1});
	}else st[x].insert((node){K-b[x],K-a[x]-1});
	if(!ls[x]) return;
	if(!rs[x]){
		if(ck(st[ls[x]],st[x])){
			cg1(st[ls[x]],st[x]);
			f[x] = f[ls[x]];
		}else{
			cg2(st[ls[x]],st[x]);
			f[x] = f[ls[x]]+1;
		}
		st[x].swap(st[ls[x]]);
		return ;
	}
	multiset<node>tmp1,tmp2;
	if(st[ls[x]].size()<st[rs[x]].size()) swap(ls[x],rs[x]);
	if(ck(st[x],st[rs[x]])){
		tmp1 = st[rs[x]];
		cg1(tmp1,st[x]);
		if(ck(tmp1,st[ls[x]])){
			cg1(st[ls[x]],tmp1);
			st[x].swap(st[ls[x]]);
			f[x] = f[ls[x]]+f[rs[x]];
		}else{
			tmp2 = st[rs[x]];
			cg2(tmp2,st[x]);
			cg1(st[ls[x]],tmp2);
			cg2(st[ls[x]],tmp1);
			st[x].swap(st[ls[x]]);
			f[x] = f[ls[x]]+f[rs[x]]+1;
		}
	}else if(ck(st[ls[x]],st[x])||ck(st[ls[x]],st[rs[x]])){
		cg2(st[x],st[rs[x]]);
		cg1(st[ls[x]],st[x]);
		swap(st[x],st[ls[x]]);
		f[x] = f[ls[x]]+f[rs[x]]+1;
	}else{
		cg2(st[ls[x]],st[x]);
		cg2(st[ls[x]],st[rs[x]]);
		st[x].swap(st[ls[x]]);
		f[x] = f[ls[x]]+f[rs[x]]+2;
	}
}
int main(){
	freopen("rugby.in","r",stdin);
	freopen("rugby.out","w",stdout);
	scanf("%d%d",&n,&K);
	for(int i = 1;i<=n;i++)
		scanf("%d%d%d%d",&a[i],&b[i],&ls[i],&rs[i]);
	dfs(1);
	if((*st[1].begin()).x>0) f[1]++;
	printf("%d",f[1]);
	return 0;
}

最后一道绝对有点问题,烦请各位指正

posted @   cztq  阅读(466)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示