B.一气贯通之刃
题目描述:
小红拿到了一棵树,她想请你寻找一条简单路径,使得这条路径不重不漏的经过所有节点。如果不存在这样的简单路径,则直接输出 −1-1−1。
思路:判断这棵树是不是一条链,如果是则输出链上最远的两个节点,否则输出-1。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
int a[N];
int main()
{
int n; cin>>n;
for(int i=1;i<n;i++)
{
int x,y; cin>>x>>y;
a[x]++,a[y]++;
}
int f=1;
for(int i=1;i<=n;i++)
{
if(a[i]>2)
{
f=0;
break;
}
}
if(f)
{
int i=1;
for(;i<=n;i++)
{
if(a[i]==1)
{
cout<<i<<' ';
break;
}
}
for(i+=1;i<=n;i++ )
{
if(a[i]==1) cout<<i;
}
}
else cout<<"-1"<<endl;
}
E、双生双宿之错
题目描述:
给一个长度为偶数的数组,要求将他变成只有两个相同数的数组,每次可以对数据加一或减一
思路:将数组排序,两半各取中位数作为目标,如果目标相同。解决方案是要么将前半部分变成中位数减1,要么将后半部分变成中位数加1,枚举这两种方案分别统计取最优。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e5+9;
int n ;
int a[N];
ll c(ll mid1,ll mid2)
{
ll ans=0;
for(int i=1,j=n/2+1;i<=n/2;i++,j++)
{
ans+=abs(mid1-a[i])+abs(mid2-a[j]);
}
return ans;
}
void slove()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n);
ll mid1,mid2;
if(n/2%2==0)
{
mid1=(a[n/4]+a[n/4+1])/2;
mid2=(a[n/2+n/4]+a[n/2+n/4+1])/2;
}
else
{
mid1=a[n/4+1];
mid2=a[n/2+n/4+1];
}
ll sum=0;
if(mid1!=mid2) sum=c(mid1,mid2);
else sum=min(c(mid1-1,mid2),c(mid1,mid2+1));
cout<<sum<<endl;
}
int main()
{
int t; cin>>t;
while(t--)
{
slove();
}
}
M.数值膨胀之美
题目描述:给一个数组,选择一个非空区间,将其中所有元素都乘以 2,求极差。
思路:显然我们优先将最小值翻倍。如果想要扩大区间,我们则选择“包含最小值和次小值”的最小区间,以此类推。
#include<bits/stdc++.h>
using namespace std;
#define int long long
struct c
{
int num;
int id;
}a[100010];
int b[100010];
bool cmp(c a,c b)
{
return a.num<b.num;
}
signed main(){
int n,i;
cin>>n;
for(i=0;i<n;i++){
cin>>a[i].num,a[i].id=i;
b[i]=a[i].num;
}
a[n].num=1e9;
sort(a,a+n,cmp);
int l=a[0].id,r=a[0].id;
int ma=max(a[0].num*2,a[n-1].num);
int res=ma-min(a[0].num*2,a[1].num);
for(i=1;i<n;i++){
while(a[i].id<l){
l--;
ma=max(ma,b[l]*2);
}
while(a[i].id>r){
r++;
ma=max(ma,b[r]*2);
}
res=min(res,ma-min(a[0].num*2,a[i+1].num));
}
cout<<res;
}