CF1000

A

link

首先,对于一个数(比如说x),它和它加一一定互质(也就是xx+1一定互质),那么它和它加一组成的区间([x,x+1])一定是好区间,也一定是最小好区间,因为除了本身[x,x+1]、两个数[x,x],[x+1,x+1]和空集不包含其他区间了,而相等两个数一定不互质,所以那两个数的区间([x,x],[x+1,x+1]),一定不是好区间。
有了这个,我们就可以说,对于任意长度大于2的区间,一定不是最小好区间,因为它一定会包含一些长度为2的区间,所以我们只要统计有多少区间长度恰好为2即可。
但是还有一个特例:[1,2],这个区间包含的[1,1]是一个好区间,所以[1,2]并不是一个最小好区间,而如果l~r的范围包括了[1,2],那么算上[1,2]而不算[1,1]与正确做法算上[1,1]而不算[1,2]对答案没有影响,所以只需要特判lr均等于1的情况。

点击查看代码
#include<bits/stdc++.h>

using namespace std;

int l,r;

void qwq(){
	cin >> l >> r;
	if(l == 1&&r == 1) cout << 1 << endl;
	else cout << r-l << endl;
}

signed main(){
	
	int t;
	cin >> t;
	while(t--) qwq();
	
	return 0;
	
} 

B

link

一个小前提:我们让w代表区间里一共有几个数,也就是rl+1
首先,我们肯定是想通过翻转把不在区间中的前w小和在区间中的非前w小换换位置(就是在区间内选想换出去的k个,在区间外选想换进来的k个,做一下翻转即可),可是我们只能做一次操作,而不在区间中的前w小可能在区间前面,也可能在区间后面。也就是说我们要么把区间里的大数和前面换,要么和后面换,也就是要么选[1,r]的前w小(和前面换),要么选[l,n]的前w小(和后面换),比较一下哪个更小即可。

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n,l,r;
int a[100005];
int b[100005]; 

void qwq(){
	
	cin >> n >> l >> r;
	for(int i = 1;i <= n;++ i)
		cin >> a[i],b[i] = a[i];
	
	sort(a+1,a+1+r);
	sort(b+l,b+1+n);
	
	int ans1 = 0,ans2 = 0;
	
	int w = r-l+1;
	for(int i = 1,j = l;i <= w;++j,++ i)
		ans1 += a[i],ans2 += b[j];
	
	cout << min(ans1,ans2) << endl;
	
}

signed main(){
	
	int t;
	cin >> t;
	while(t--) qwq();
	
	return 0;
	
}

C

link

脑补一棵树,我们想如果一个点有k条出边,那么它将会有k1个儿子(还有父亲的那一条出边),那么如果把它删除,将会出现k个联通块(上面的和它所有的儿子)。
这样,删除一个点的就非常好做了。
正常来说,第二个点应该和第一个点是差不多的,但是,

看这个图,我们第一次删除的是灰色点,那么我们要是第二次删除紫色点,那么仍然会多出它出边数个联通块,也就是4个,但是如果我们第二次删除的是黄色点,那么问题来了,(大家可以脑补一下画面),我们第一次删除灰色点时,它连出去的边也没有了,那么黄色点将会少一条出边。
这时有人会说了,那么我们直接把和第一次选的点相邻的点出边数减一不就行了吗,那么看这个图,

我们想要把和第一次选的点相邻的点出边数减一,我们就要存第一次选的点的编号,一个黄色点和两个紫色点都是最优答案,如果我们存的是黄色点怎么办,答案会少(大家这里可以手推一下,选那两个紫色点是最优方案)。
所以我们就要换一种实现方式。我们不存第一次选的点,我们只存最大的出边数,再存一下每个点与几个出边数为最大出边数的点相邻(也就是与几个可以作为第一次选的点的点相邻)(包括它自己,原因见下),补充一下,我们把以作为第一次选的点的点称作最优点,那么我们一定可以知道第一次选的点一定会在最优点中选,如果它相邻的最优点个数和所有最优点个数相等,那么它就一定会和最优点相邻,直接减一即可,否则不需要减一。
那么为什么统计相邻最优点个数时要把本身加上呢?因为如果本身是一个最优点,而且最优点均在它周围,这种情况是要减一的,因为一定和最优点相邻。这时如果不加本身,会少数一个,认为还有一个最优点不与它相邻(其实这个最优点就是它本身),就不会减一了,答案就会错。
这里最终答案是要减一的,因为这两个点之间的那一部分会被两个点分别算一遍,一共算两遍,要去掉一遍。

点击查看代码
#include<bits/stdc++.h>

using namespace std;

int n;
vector<int> ed[200005];
int out[200005];
int lg[200005];

void qwq(){
	
	cin >> n;
	for(int i = 1;i <= n;++ i)
		ed[i].clear(),out[i] = 0,lg[i] = 0;
	for(int i = 1;i < n;++ i){
		int u,v;
		cin >> u >> v;
		ed[v].push_back(u);
		ed[u].push_back(v);
		out[v]++;
		out[u]++;
	}
	
	int w = 0,ans = 0,sum = 0;
	
	for(int i = 1;i <= n;++ i)
		ans = max(ans,out[i]);
	
	for(int i = 1;i <= n;++ i){
		if(out[i] == ans){
			w++;
			lg[i]++;
			for(int j = 0;j < ed[i].size();++ j){
				int v = ed[i][j];
				lg[v]++;
			}
		}
	}
	
	for(int i = 1;i <= n;++ i){
		if(w == 1&&out[i] == ans) continue;
		//如果只有一个最优点还就是i,那么一定不可能把它作为第二次选的点,跳过即可
		if(lg[i] != w)
			sum = max(sum,ans+out[i]);
		else sum = max(sum,ans+out[i]-1);
	}
	
	cout << sum-1 << endl;
	
}

signed main(){
	
	int t;
	cin >> t;
	while(t--) qwq();
	
	return 0;
	
} 

D

link

我们考虑想让三角形尽可能大,一定要从两头选点。
那么我们考虑第i步到第i+1步。
1.如果有一边没法选了,那么撤回前一次选这边的那一步在接着选。
2.看看在上面选两个更好还是在下面选两个更好。
3.更新上下各选了几组两个。
那么一共可以选几次呢?(我们让nm小)如果n的两倍还不到m,那么最多只能组成n个三角形(头在n那,脚在m那),否则一定是n+m3(感性理解一下)。

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int read(){
	int x = 0,y = 1;
	char ch = getchar();
	while(ch > '9'||ch < '0'){
		if(ch == '-') y = -1;
		ch = getchar();
	}
	while(ch >= '0'&&ch <= '9'){
		x = x*10+ch-48;
		ch = getchar();
	}
	return x*y;
}

int n,m;
int a[200005];
int b[200005];
int c[200005];
int d[200005];
int f[200005];

void qwq(){
	
	n = read();m = read(); 
	
	if(n > m){
		swap(n,m);
		for(int j = 1;j <= m;++ j)
			b[j] = read();
		for(int i = 1;i <= n;++ i)
			a[i] = read();
	}
	else{
		for(int i = 1;i <= n;++ i)
			a[i] = read();
		for(int j = 1;j <= m;++ j)
			b[j] = read();
	}
	
	sort(a+1,a+1+n);
	sort(b+1,b+1+m);
	
	int k;
	if(2*n <= m) k = n;
	else k = (n+m)/3;
	
	printf("%lld\n",k);
	
	for(int i = 1;2*i <= n;++ i)
		c[i] = a[n-i+1]-a[i];
	for(int j = 1;2*j <= m;++ j)
		d[j] = b[m-j+1]-b[j];
	
	int sta = 0,stb = 0,ans = 0;
	for(int i = 1;i <= k;++ i){
		if(2*sta+stb == n){
			ans = ans-c[sta]+d[stb+1];
			stb++;sta--;
		}
		if(2*stb+sta == m){
			ans = ans-d[stb]+c[sta+1];
			sta++;stb--;
		}
		if((2*sta+stb <= n-2)&&(2*stb+sta == m-1||c[sta+1] > d[stb+1])) ans += c[sta+1],sta++;
		else ans += d[stb+1],stb++;
		f[i] = ans;
	}
	
	for(int i = 1;i <= k;++ i)
		printf("%lld ",f[i]);
	puts("");
	
}

signed main(){
	
	int t = read();
	while(t--) qwq();
	
	return 0;
	
}
posted @   不认命,就是哪吒的命!  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示