Codeforces1337

本文精选了四道算法竞赛题目并提供了详细的解题思路及代码实现,包括三角形边长构造、龙血量计算、树中节点选择以及三序列元素组合问题,涵盖了从简单到复杂的算法设计与分析。

A
题意:给你4个从小到大的数a,b,c,d
找出任一一组分别在[a,b],[b,c],[c,d]中的三个数,使得他们可以构成三角形的三边长。题目保证答案存在。
解:b,c,c 必定符合题意。输出即可

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cstring>
#define inf 2147483647
#define N 1000010
#define p(a) putchar(a)
#define For(i,a,b) for(long long i=a;i<=b;++i)
#define ll long long 
using namespace std;
int a[5],T;
int ans[5];
signed main(){
	//freopen("test.in","r",stdin);
	cin>>T;
	while(T--){
		cin>>a[1]>>a[2]>>a[3]>>a[4];
		printf("%d %d %d\n",a[2],a[3],a[3]);
	}
    return 0;
}

B
题意:有一只大龙血量为hp,你可以使用n次技能A和m次技能B。问你是否能够打败它(使他血量低于0)
技能A hp=》[hp/2]+10;
技能B hp-=10;
解:
经计算,对于任意hp>20,技能A会使hp减少,而当hp<20,技能A会使hp增加。技能B一定会使hp减少。最优伤害计算方法为当hp>20,使用技能A,当hp<=20 使用技能B。由于数据范围比较小,可以直接计算。

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cstring>
#define inf 2147483647
#define N 1000010
#define p(a) putchar(a)
#define For(i,a,b) for(long long i=a;i<=b;++i)
#define ll long long 
using namespace std;
int hp,n,m,T;
signed main(){
	//freopen("test.in","r",stdin);
	cin>>T;
	while(T--){
		cin>>hp>>n>>m;
		while(n--&&hp>20){
			hp=hp/2+10;
		}
		while(m--){
			hp-=10;
		}
		if(hp<=0)cout<<"YES";
		else cout<<"NO";
		cout<<"\n";
	}
    return 0;
}

C
题目大意;给一棵树,选择k个点使得这k个结点往祖先结点回溯时非k点的数目和最大。
因为每个子树的深度越大越优,所以每颗子树上结点的选取相对顺序可以确定,并且可以计算每个结点对答案的贡献深度减去儿子的数量即dp[n]-sons[n].计算,排序即可。

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cstring>
#define inf 2147483647
#define N 1000010
#define p(a) putchar(a)
#define For(i,a,b) for(long long i=a;i<=b;++i)
#define ll long long 
using namespace std;
const ll maxn=2e5+10;
ll n,k;
ll tol=0,first[maxn];
struct edge{
	ll to,next;
}e[maxn*2];
void addedge(ll from,ll too){
	tol++;
	e[tol].to=too;
	e[tol].next=first[from];
	first[from]=tol;
}
ll vis[maxn],d[maxn],sons[maxn];
ll a[maxn];
void spfa(){
	memset(d,0x3f,sizeof(d));
	d[1]=0;
	queue<ll>q;
	q.push(1);
	vis[1]=1;
	while(!q.empty()){
		ll now=q.front();q.pop();
		for(ll i=first[now];i;i=e[i].next){
			ll v=e[i].to;
			if(vis[v])continue;
			vis[v]=1;
			d[v]=d[now]+1;
			q.push(v);
		}
	}
}
void dfs(ll x){
	for(ll i=first[x];i;i=e[i].next){
		ll v=e[i].to;
		if(d[v]==d[x]+1){
			dfs(v);
			sons[x]+=(sons[v]+1);
		}
	}
}
signed main(){
	//freopen("test.in","r",stdin);
	cin>>n>>k;
	for(ll x,y,i=2;i<=n;i++){
		cin>>x>>y;
		addedge(x,y);
		addedge(y,x);
	}
	spfa();
	dfs(1);
	for(ll i=1;i<=n;i++){
		a[i]=d[i]-sons[i];
	}
	sort(a+1,a+n+1);
	ll temp=n,ans=0;
	while(k--){
		ans+=a[temp--];
	}
	cout<<ans<<'\n';
    return 0;
}

D:
题意:给三个序列r,g,b;
每个序列选择一个数 x,y,z;
找出最小的(x−y)2+(y−z)2+(z−x)2最小;
解:
x 预处理每个x的第一个比它大的lessy,lessz;第一个比他小的hugey,hugez;
x为第二大(中间数)的最优组合(x,y,z)必在(x,lessy,hugez)和(x,hugey,lessz)遍历求出;
y,z 同理。

#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cstring>
#define inf 2147483647
#define N 1000010
#define p(a) putchar(a)
#define For(i,a,b) for(long long i=a;i<=b;++i)
#define ll unsigned long long 
using namespace std;
const ll maxn=1e5+10;
ll T;
ll nr,ng,nb;
ll r[maxn],g[maxn],b[maxn];
ll tolans=0;
ll ans[15][maxn];
ll sum(ll x,ll y,ll z){
	return (x-y)*(x-y)+(y-z)*(y-z)+(x-z)*(x-z);
}
void getnext(ll array[],ll size1,ll brray[],ll size2){
	tolans++;
	ll tol=1;
	for(ll i=1;i<=size1;i++){
		while(brray[tol]<array[i]&&tol<size2)tol++;
		ans[tolans][i]=brray[tol];
	}
}
void getlast(ll array[],ll size1,ll brray[],ll size2){
	tolans++;
	ll tol=size2;
	for(ll i=size1;i>=1;i--){
		while(brray[tol]>array[i]&&tol>1)tol--;
		ans[tolans][i]=brray[tol];
	}
}
signed main(){
	//freopen("test.in","r",stdin);
	cin>>T;
	while(T--){
		tolans=0;
		ll anss=0x3fffffffffffffff;
		cin>>nr>>ng>>nb;
		for(ll i=1;i<=nr;i++)cin>>r[i];
		for(ll i=1;i<=ng;i++)cin>>g[i];
		for(ll i=1;i<=nb;i++)cin>>b[i];
		sort(r+1,r+nr+1);sort(g+1,g+ng+1);sort(b+1,b+nb+1);
		getnext(r,nr,b,nb);
		getlast(r,nr,g,ng);
		getnext(r,nr,g,ng);
		getlast(r,nr,b,nb);
 
		getnext(b,nb,g,ng);
		getlast(b,nb,r,nr);
		getnext(b,nb,r,nr);
		getlast(b,nb,g,ng);
 
		getnext(g,ng,r,nr);
		getlast(g,ng,b,nb);
		getnext(g,ng,b,nb);
		getlast(g,ng,r,nr);
 
		for(ll i=1;i<=nr;i++){
			ll x=sum(r[i],ans[1][i],ans[2][i]);
			ll y=sum(r[i],ans[3][i],ans[4][i]);
			anss=min(anss,sum(r[i],ans[1][i],ans[2][i]));
			anss=min(anss,sum(r[i],ans[3][i],ans[4][i]));
		}
		for(ll i=1;i<=nb;i++){
			anss=min(anss,sum(b[i],ans[5][i],ans[6][i]));
			anss=min(anss,sum(b[i],ans[7][i],ans[8][i]));
		}
		for(ll i=1;i<=ng;i++){
			anss=min(anss,sum(g[i],ans[9][i],ans[10][i]));
			anss=min(anss,sum(g[i],ans[11][i],ans[12][i]));
		}
		cout<<anss<<'\n';
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值