CF1000
A
link
首先,对于一个数(比如说
有了这个,我们就可以说,对于任意长度大于
但是还有一个特例:
点击查看代码
#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
一个小前提:我们让
首先,我们肯定是想通过翻转把不在区间中的前
点击查看代码
#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
脑补一棵树,我们想如果一个点有
这样,删除一个点的就非常好做了。
正常来说,第二个点应该和第一个点是差不多的,但是,
看这个图,我们第一次删除的是灰色点,那么我们要是第二次删除紫色点,那么仍然会多出它出边数个联通块,也就是
这时有人会说了,那么我们直接把和第一次选的点相邻的点出边数减一不就行了吗,那么看这个图,
我们想要把和第一次选的点相邻的点出边数减一,我们就要存第一次选的点的编号,一个黄色点和两个紫色点都是最优答案,如果我们存的是黄色点怎么办,答案会少(大家这里可以手推一下,选那两个紫色点是最优方案)。
所以我们就要换一种实现方式。我们不存第一次选的点,我们只存最大的出边数,再存一下每个点与几个出边数为最大出边数的点相邻(也就是与几个可以作为第一次选的点的点相邻)(包括它自己,原因见下),补充一下,我们把以作为第一次选的点的点称作最优点,那么我们一定可以知道第一次选的点一定会在最优点中选,如果它相邻的最优点个数和所有最优点个数相等,那么它就一定会和最优点相邻,直接减一即可,否则不需要减一。
那么为什么统计相邻最优点个数时要把本身加上呢?因为如果本身是一个最优点,而且最优点均在它周围,这种情况是要减一的,因为一定和最优点相邻。这时如果不加本身,会少数一个,认为还有一个最优点不与它相邻(其实这个最优点就是它本身),就不会减一了,答案就会错。
这里最终答案是要减一的,因为这两个点之间的那一部分会被两个点分别算一遍,一共算两遍,要去掉一遍。
点击查看代码
#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
我们考虑想让三角形尽可能大,一定要从两头选点。
那么我们考虑第
1.如果有一边没法选了,那么撤回前一次选这边的那一步在接着选。
2.看看在上面选两个更好还是在下面选两个更好。
3.更新上下各选了几组两个。
那么一共可以选几次呢?(我们让
点击查看代码
#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;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析