2020 GDUT Rating Contest III (Div2)

2020 GDUT Rating Contest III (Div2)

A Wormhole Sort
题意:
给出N个打乱顺序的数,和M条边(a,b,c)表示在a位置的数可以和在b位置的数交换,这条边的大小是c,问要使这组数恢复升序需要经过的大小最小的最大的边是多大。

解题思路:
直接二分答案,通过把大小大于等于答案的边用来连成一个连通块,看乱序的点是否在同一个连通块来判断该答案是否合法。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{
	int from,to,size;
}edge[100005];
int cow[100005],f[100005];
int n;
bool cmp(node a,node b){
	return a.size>b.size;
}
int father(int u){
	return f[u]==u?u:f[u]=father(f[u]);
}
void merge(int x,int y){
	int fx=father(x),fy=father(y);
	f[fx]=f[fy];
	return;
}
bool check(int x){
	for (int i=1;i<=n;i++)
		f[i]=i;
	for (int i=1;i<=x;i++)
		merge(edge[i].from,edge[i].to);
	for (int i=1;i<=n;i++)
		if (father(i)!=father(cow[i])) return false;
	return true;
}
int main(){
	int m;
	scanf("%d %d",&n,&m);
	bool flg=true;
	for (int i=1;i<=n;i++){
		scanf("%d",&cow[i]);
		if (cow[i]!=i) flg=false;
	}
	for (int i=1;i<=m;i++)
		scanf("%d %d %d",&edge[i].from,&edge[i].to,&edge[i].size);
	if (flg) 
	{
		printf("-1\n");
		return 0;
	}
	sort(edge+1,edge+m+1,cmp);
	int l=0,r=m;
	while (r-l>1){
		int mid=(l+r)/2;
		if (check(mid)) r=mid;
		else l=mid;
	}
	printf("%d\n",edge[r].size);
	return 0;
}

B Loan Repayment
题意:
John欠了N加仑牛奶需要在K天内还清,他每天会最少还M加仑牛奶。在已经还了G加仑奶之后,对于一个正整数X,John会每天还max((N-G)/X,M)加仑奶。
求X的最大值。
1<=N,M,K<=1e12

解题思路:
二分答案,如果直接模拟的话会出现连续很多天给Y加仑奶的情况导致超时,所以只要用数学优化一下模拟的过程,让每次换奶的时候Y的值都会发生变化即可。

#include<cstdio> 
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
using namespace std;
long long n,k,m;
bool check(long long x){
	long long cnt=1LL*k*m;
	long long g=0,d;
	long long y=n/x;
	int t=0;
	while (y>m&&t<=k)
	{
		if (ceil(1.0*(n-y*x-g)/y)+t<=k) d=ceil(1.0*(n-y*x-g)/y+0.000000000000001);
		else d=k-t+1;
		t+=d;
		g+=y*d;
		cnt+=(y-m)*d;
		if (cnt>=n) return true;
		y=(n-g)/x;
	}
	return false;
}
int main(){
	scanf("%lld %lld %lld",&n,&k,&m);
	long long l=1,r=1e12+1;
	while (r-l>1){
		long long mid=(l+r)/2;
		if (check(mid)) l=mid;
		else r=mid;
	}
	printf("%lld\n",l);
	return 0;
}

D Race
题意:
Bessie要跑K米,她每个时刻可以加速1或者减速1或者匀速跑,她结束跑步时速度不能高于X,现在给出N个X,问每个X对应需要的结束跑步的时间。

解题思路:
二分找最大速度,然后模拟一下算出时间即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int q,len,n,k;
bool check(long long x)
{
	long long a=1LL*(1+x)*x/2;
	long long b;
	if (x<q) b=0;
	else b=(q+x-1)*(x-q)/2;
	len=a+b;
	if (a+b<=k) return true;
	else return false; 
}
int main(){
	scanf("%d %d",&k,&n);
	int ans;
	for (int i=1;i<=n;i++){
		scanf("%d",&q);
		int l=1,r=1000000;
		while (l<=r)
		{
			int mid=(l+r)/2;
			if (check(mid))
			{
				ans=mid;
				l=mid+1;
			}
			else r=mid-1;
		}
		bool x=check(ans);
		long long t=ans;
		if (ans>=q) t+=ans-q;
		long long last=k-len;
		if (last!=0)
		{
			t+=last/ans;
			if (last%ans!=0) t++;
		} 
		printf("%lld\n",t);
	}
}

E.Word Processor
题意:
给出一个有N个单词的句子。要求拆成每行不超过K个字母输出(不能拆开完整的单词)。

解题思路:
直接判每个单词长度,如果符合要求就输出。

#include<cstdio> 
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
using namespace std;
int main(){
	int n,k;
	string s[105];
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;i++)
		cin>>s[i];
	for (int i=1;i<=n;){
		int cnt=s[i].size();
		int j=i+1;
		while (cnt+s[j].size()<=k&&j<=n) {cnt+=s[j].size();j++;}
		for (int k=i;k<j;k++)
			cout<<s[k]<<" ";
		printf("\n");
		i=j;
	}
}

H:Photoshoot
题意:
给长为N-1个数列a,求无相同元素的数列B使得对于1到n-1都有b[i]+b[i+1]=a[i],且对于所有的b[i]有1<=b[i]<=N。输出字典序最小的方案

解题思路:
直接从1开始枚举b[1]即可,找到第一种符合的方案就是字典序最小的方案。

#include<cstdio> 
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
using namespace std;
int n;
int a[1005],b[1005];
bool vis[1005];
bool check(int x){
	memset(vis,false,sizeof(vis));
	a[1]=x;vis[x]=true;
	for (int i=1;i<n;i++){
		if (b[i]-a[i]<=0||b[i]-a[i]>n) return false;
		if (vis[b[i]-a[i]]) return false;
		a[i+1]=b[i]-a[i];
		vis[b[i]-a[i]]=true;
	}
	return true;
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<n;i++)
		scanf("%d",&b[i]);
	for (int i=1;i<b[1];i++)
		if (check(i))
		{
			for (int j=1;j<=n;j++)
				printf("%d ",a[j]);
			return 0;
		}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值