Codeforces Round #601 (Div. 2) 2019.11.19

A. Changing Volume

题意:

给定两个数a和b,与六种操作(−5,−2,−1,+1,+2,+5)。问a通过多少次操作可以变成b。

思路:

因为无论是想让a变大还是变小,都有三种相同的操作,所以就不用分类讨论a是否大于b了。读入a跟b后直接取他们相差的绝对值。根据贪心先将差值除上5,再加上对5取模的结果除2,再加上差值对5取模后再对2取模的结果就是答案了。
代码如下:

#include
#include
 using namespace std;
 int main()
 {
 	int t;
 	scanf("%d",&t);
 	while(t--){
 		int a,b;
 	scanf("%d%d",&a,&b);
 	int x=abs(a-b);
 	int ans1=0,ans2=0;
 	ans1+=x/5;
 	ans1+=(x%5)/2;
 	ans1+=((x%5)%2);
 	cout<<ans1<<endl;
	 }
	return 0;
 }

B. Fridge Lockers

题意:

给你n个冰箱与m条链锁,想打开该冰箱就必须知道与之所有相连链锁的密码,并且一个冰箱的主人知道与该冰箱相连的所有链锁的密码。定义一个冰箱是安全的当且仅当只有该冰箱的主人能打开该冰箱,构造一条链锁的价值为与之相连的两个冰箱价值的总和。现在问你,有n个冰箱并且能放m条链锁,求在每个冰箱都是安全情况下构造m条链锁的最小价值。如果放置m条链锁不能使n个冰箱都安全则输出-1。并且两个冰箱之间可以有多条锁

思路:

先考虑什么时候会有冰箱不安全,很显然当n=1或者n=2时冰箱是不安全的。再仔细考虑,当m 再来考虑最小价值,要想价值最小肯定想的是在每个冰箱都安全的情况下再把价值最小的两个冰箱不停的加重边(因为题目说了可以有重边),那要怎么确保每个冰箱都是安全了并且价值还最小呢,那就是所有冰箱连成一个环。(不理解的同学可以多画几个图理解一下)
代码如下:

#include
#include
 using namespace std;
 const int maxn=1e3+5;
 struct node{
 	int x,i;
 }a[maxn];
 int cmp(node x,node y)
 {
 	return x.x<y.x;
 }
 int main()
 {
 	int t,n,m,sum;
 	scanf("%d",&t);
 	while(t--){
 		sum=0;
 		scanf("%d%d",&n,&m);
 		for(int i=1;i<=n;i++){
 			scanf("%d",&a[i].x);
 			a[i].i=i;
 			sum+=a[i].x;
		 }
		if(n==1||n==2||n>m){
			cout<<"-1"<<endl;
			continue;
		}
		else
			sort(a+1,a+1+n,cmp);
		long long ans=sum*2+(a[2].x+a[1].x)*(m-n);
		cout<<ans<<endl;
		for(int i=1;i<=n;i++){
			if(i==n)
				cout<<"1"<<" "<<i<<endl;
			else
				cout<<i<<" "<<i+1<<endl;
		}
		for(int i=n+1;i<=m;i++)
			cout<<a[1].i<<" "<<a[2].i<<endl;
	}
	return 0; 
 }

C. League of Leesins

题意:

给你一个数n,给n-3个长度为3的序列,分别是[ai,ai+1,ai+2],每个序列内的顺序是混乱的,并且序列也不是按照顺序给的,让你求出原序列。

思路:

很容易就能知道原序列的第一个数与最后一个数在所有序列中的出现次数都是只为1,并且第二个数与倒数第二个数出现的次数都只为2。因此我们只需要用vector记录与i元素在同一个序列中一起出现过的元素,与vis数组记录给元素是否已经被输出,cnt数组记录元素出现过几次。然后首先找出出现次数为1的元素令其为a,再通过vector找出出现次数为2的元素另其为b,接下来可以通过a来找到c,也就是与a,b,在同一序列的数,此时令a=b,b=c,不断去查找c就可以找到原序列了。
代码如下:

#include
#include
#include
#include
using namespace std;
const int maxn = 1e5+10;
vector<int> p[maxn];
int cnt[maxn],vis[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n-2;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		p[a].push_back(b),p[a].push_back(c);
		p[b].push_back(a),p[b].push_back(c);
		p[c].push_back(a),p[c].push_back(b);
		cnt[a]++,cnt[b]++,cnt[c]++;
	}
	int a,b;
	for(int i=1;i<=n;i++){
		if(cnt[i]==1){
			vis[i]=1;
			a=i;
			break;
		}
	}
	for(int i=0;i<p[a].size();i++){
		if(cnt[p[a][i]]==2){
			b=p[a][i];
			vis[b]=1;
			break;
		}
	}
	printf("%d %d",a,b);
	for(int i=3;i<=n;i++){
		int temp=0;
		for(int i=0;i<p[a].size();i++){
			if(!vis[p[a][i]]){
				temp=p[a][i];
				vis[p[a][i]]=1;
				printf(" %d",temp);
				break;
			}
		}
		a=b;
		b=temp;
	}
	return 0;
}

D. Feeding Chicken

题意:

给一个r*c大小的格子,每个格子中可能会有米,你有k只鸡,要求将k只鸡放进这些格子中去养。要求每只鸡可以吃的米尽可能相同,并且每只鸡的领地不能相互交叉,输出,每只鸡的领地可以用大写字母小写字母数字在格子中表示

思路:

其实,一个鸡最少吃sum(所有米的个数)/k个米,最多吃sum/k+1个米,然后用蛇形走一遍所有格子,以保持所有鸡的领地不交叉,数到一直鸡能吃的最多米数,就换一只鸡继续吃(也就是用另一个符号去记录下一只只鸡的领地),整体来说思路比较简单,就是模拟起来可能比较复杂。
代码如下:

#include
#include
#include
 using namespace std;
 const int maxn=105;
 char str[maxn][maxn];
 int mp[maxn][maxn],ans[maxn][maxn];
 int r,c,k,sum;
 char get(char ch)
 {
 	if(ch=='9') return 'a';
 	if(ch=='z') return 'A';
 	return ++ch;
 }
 void solve()
 {
 	int ma,mi,a,b;
 	ma=sum/k+1;
 	mi=sum/k;
 	a=sum%k;
 	if(a) b=ma;
 	else b=mi;
	char ch='0';
	int j=1,flag=1;
	for(int i=1;i<=r;i++){
		for(int p=1;p<=c;p++){
			ans[i][j]=ch;
			if(mp[i][j]==1)
				b--;
			if(!b){
				k--;
				if(k>0)
					ch=get(ch);
				a--;
				if(a>0) b=ma;
				else b=mi;
			}
			j+=flag;
		}
		if(i%2) j=c,flag=-1;
		else j=1,flag=1;
	}
	 for(int i = 1;i <= r;i++){
        for(int j = 1;j <= c;j++){
            printf("%c",ans[i][j]);
        }
        printf("\n");
    }
 }
 int main()
 {
 	int t;
 	scanf("%d",&t);
 	while(t--){
 		sum=0;
 		scanf("%d%d%d",&r,&c,&k);
 		memset(mp,0,sizeof(mp));
 		for(int i=1;i<=r;i++){
		 	scanf("%s",str[i]);
 			for(int j=1;j<=c;j++){
 				if(str[i][j-1]=='R'){
 					sum++;
 					mp[i][j]=1;
				 }
			 }
		 }
		solve();
	 }
	return 0;
  } ```

你可能感兴趣的:(codeforces)