Practice on Codeforces and Atcoder in March
cf1798d
题意:重排序列,使得其中连续子序列和的绝对值最大的最大值小于序列最大值减最小值,序列和为0
考虑这样一种构造方案:
正负数分类,0直接不管
然后记录当前和sum,当sum非负时,加上一个负数,当sum是负数时,加上一个正数即可
正确性证明:
显然前缀和都是合法的。考虑计算前缀和数组,满足性质:最小的sum小于最小值,最大的sum大于等于最大值。 那么显然合法
无解的情况就是全0
/*
分讨:
1. sum<mx-mn-->mx>0,mn<0-->sum<mx-mn
2. -sum<mx-mn->mx>0,mn<0-->sum>mn-mx
不妨思考一个更强的条件
mn<=sum<=mx
一种合理的构造方式是:
当前sum>0,加一个负数
当前sum<0,加一个正数
当前sum=0,随便加
Why?
由于和是0,则按照这样加sum最大为mx(0+mx),最小为mn(0+mn)
*/
signed main(){
ios::sync_with_stdio(false);
cin>>t;
while(t--){
int num1=0,tot=0,num2=0,mx=0,mn=0;cnt=0;
cin>>n;
for(int i=1;i<=n;i++){
int x;cin>>x;
mx=max(mx,x);mn=min(mn,x);
if(x>0)a[++num1]=x;
else if(x<0)b[++num2]=x;
else ans[++tot]=0;
}
if(mx==mn){
cout<<"No\n";continue;
}
int sum=0,l=1,r=1;
while(l<=num1&&r<=num2){
if(sum<0)sum+=a[l],ans[++tot]=a[l],l++;
else sum+=b[r],ans[++tot]=b[r],r++;
}
while(l<=num1)ans[++tot]=a[l],l++;
while(r<=num2)ans[++tot]=b[r],r++;
cout<<"Yes\n";
for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
cout<<"\n";
}
}
CF1805D
给定一颗树,求
联系到树的直径,设直径长为
则
引理:
当
证明:
现在我们证明了
采用反证法
假设会形成一个
直径不在这里,所以一定两端点到这个连通块的最大距离
引理成立。
所以可以以两个直径端点进行BFS,然后倒序处理删连通块即可
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<cstring>
#define N 300400
using namespace std;
int s,t,vis[N],dis[N][3],n,m,head[N],ver[N],nxt[N],tot,ans[N],f[N];
vector<int>cnt[N],cnt1[N];
void add(int u,int v){
nxt[++tot]=head[u],ver[head[u]=tot]=v;
}
void bfs(int s,int id){
queue<int>q;
memset(vis,0,sizeof vis);
vis[s]=1;
q.push(s);
dis[s][id]=0;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=nxt[i]){
int v=ver[i];
if(vis[v])continue;
dis[v][id]=dis[u][id]+1;
q.push(v);vis[v]=1;
if(id==0)cnt[dis[v][id]].push_back(v);
if(id==1)cnt1[dis[v][id]].push_back(v);
}
}
}
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
int main(){
// ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
add(u,v);add(v,u);
}
bfs(1,2);s=-1;int mx=-1;
for(int i=1;i<=n;i++){
if(dis[i][2]>mx){
mx=dis[i][2];s=i;
}
}
bfs(s,1);
mx=-1;
for(int i=1;i<=n;i++){
if(dis[i][1]>mx){
mx=dis[i][1];t=i;
}
}
bfs(t,0);int sum=n;
for(int i=1;i<=n;i++)f[i]=i;
//cout<<s<<" "<<t<<"\n";
for(int i=mx;i;--i){
for(int j=0;j<cnt1[i].size();j++){
int u=cnt1[i][j];u=find(u);
if(u!=find(s)){
sum--;
f[u]=find(s);
}
}
for(int j=0;j<cnt[i].size();j++){
int u=cnt[i][j];u=find(u);
if(u==find(t))continue;
f[u]=find(t);
sum--;
}
ans[i]=sum;
}
for(int i=1;i<=n;i++){
if(i>mx)cout<<n<<" ";
else cout<<ans[i]<<" ";
}
return 0;
}
CF1806C
首先,让我们来手推一下。
我们已知的条件是:
以前两个式子为例,有:
这个方程有两种可能:
或
由于式子一共有
进而对于第一种情况,我们可以确定出当
对于第二种情况,所有值都相等,则有:
显然,对于
需要注意,当
综上所述,有:
- 对于
,这个最优的 为 两种可能,距离都是 - 对于
,好的数组有且仅有: 及其排列 - 对于
为偶数且 ,好的数组有且仅有 及其排列 - 对于
为奇数且 ,好的数组有且仅有
对于
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[2060606],n,T;
signed main(){
ios::sync_with_stdio(false);
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n<<1;i++)cin>>a[i];
if(n==1){
cout<<abs(a[1]-a[2])<<"\n";
}
else if(n==2){
int ans1=0;
for(int i=1;i<=n<<1;i++)ans1+=abs(a[i]-2);
int ans2=0;
for(int i=1;i<=n<<1;i++)ans2+=abs(a[i]);
int ans3=0;
for(int i=1;i<=n<<1;i++)ans3+=abs(a[i]+1);
int mx=0x3f3f3f3f3f3f;
for(int i=1;i<=n<<1;i++)mx=min(mx,abs(a[i]-n)-abs(a[i]+1));
ans3+=mx;
ans2=min(ans2,ans3);
cout<<min(ans1,ans2)<<"\n";
}
else if((n&1)==0){
int ans2=0;
for(int i=1;i<=n<<1;i++)ans2+=abs(a[i]);
int ans3=0;
for(int i=1;i<=n<<1;i++)ans3+=abs(a[i]+1);
int mx=0x3f3f3f3f3f3f;
for(int i=1;i<=n<<1;i++)mx=min(mx,abs(a[i]-n)-abs(a[i]+1));
ans3+=mx;
cout<<min(ans2,ans3)<<"\n";
}
else {
int ans2=0;
for(int i=1;i<=n<<1;i++)ans2+=abs(a[i]);
cout<<ans2<<"\n";
}
}
}
CF1810D
不等式缩放即可
一组
相同的,询问时仅需要判断在这个范围内唯一确定即可
设询问
则最大的
然后就只需要判断这个
可能越界的就是
注意特判
signed main(){
cin>>t;
while(t--){
int q;cin>>q;
int mn=0,mx=1e18,num=0;
while(q--){
int opt,a,b,n;
cin>>opt>>a>>b;
if(opt==1){
cin>>n;
int new_mn,new_mx;
if(n>1)new_mn=a*(n-1)-b*(n-2)+1;
else new_mn=0;
new_mx=a*n-b*(n-1);
if(new_mx>=mn&&new_mn<=mx){
mx=min(mx,new_mx);
mn=max(new_mn,mn);
f[++num]=1;continue;
}
f[++num]=0;
}
else {
n=(mx-b+a-b-1)/(a-b);n=max(n,1ll);
if((n-1)*a-(n-2)*b>=mn&&n!=1)f[++num]=-1;
else f[++num]=n;
}
}
for(int i=1;i<=num;i++)cout<<f[i]<<" ";
cout<<"\n";
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!