Codeforces Round #312 (Div. 2)

嗯 因为正好昨晚有一场CF的比赛,昨天就并没有更新blog,CF的时间还是让人感到非常的不舒服啊Q+Q。人家已经完全不想熬夜了,但是一场比赛就强行等到1点半出结果。

一直弄到今天早晨精神还行,下午就有点犯困Q+Q。我觉得我肯定是饿了而不是困了。言归正传~


A. Lala Land and Apple Trees
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Amr lives in Lala Land. Lala Land is a very beautiful country that is located on a coordinate line. Lala Land is famous with its apple trees growing everywhere.

Lala Land has exactly n apple trees. Tree number i is located in a position xi and has ai apples growing on it. Amr wants to collect apples from the apple trees. Amr currently stands in x = 0 position. At the beginning, he can choose whether to go right or left. He'll continue in his direction until he meets an apple tree he didn't visit before. He'll take all of its apples and then reverse his direction, continue walking in this direction until he meets another apple tree he didn't visit before and so on. In the other words, Amr reverses his direction when visiting each new apple tree. Amr will stop collecting apples when there are no more trees he didn't visit in the direction he is facing.

What is the maximum number of apples he can collect?

Input

The first line contains one number n (1 ≤ n ≤ 100), the number of apple trees in Lala Land.

The following n lines contains two integers each xiai ( - 105 ≤ xi ≤ 105xi ≠ 01 ≤ ai ≤ 105), representing the position of the i-th tree and number of apples on it.

It's guaranteed that there is at most one apple tree at each coordinate. It's guaranteed that no tree grows in point 0.

Output

Output the maximum number of apples Amr can collect.

题意:

有n棵苹果树被安置在x轴上,每颗苹果树都有自己的苹果数。人的初始位置是x=0,你可以选择往x轴正方向走或者负方向走,并且你在该方向上遇到第一颗苹果树时,你将会摘下它的所有苹果,并且反向行走。问你最多可以摘取多少个苹果。


思路:

挺基础的,就按照x轴坐标排个序,走的方向也可以直接算出来,如果x轴负方向上的苹果树比较多,肯定先往x轴负方向走,反之亦然。如果非要有一个注意的话就是最后摘取的苹果树数量是 2*min(x_f,x_z)+1。x_f表示负方向上的苹果树数量。x_z表示正方向上的苹果树数量。  然后贴个代码:


#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
struct node{
	int pos,val;
};
node a[105];
int cmp(node a,node b){
	if (a.pos!=b.pos)
		return (a.pos<b.pos);
	return (a.val<b.val);
}
int ri,le;
int main(){
	scanf("%d",&n);
	ri=le=0;
	for (int i=0;i<n;i++){
		scanf("%d%d",&a[i].pos,&a[i].val);
		if (a[i].pos>0)
			ri++;
		if (a[i].pos<0)
			le++;
	}
	sort(a,a+n,cmp);
	if (le>ri){
		int ans=0;
		for (int i=n-1;i>=n-1-2*ri;i--){
			if (i<0)
				break;
			ans+=a[i].val;
		}
		printf("%d\n",ans);
	}
	else{
		int ans=0;
		for (int i=0;i<=2*le;i++){
			if (i>=n)
				break;
			ans+=a[i].val;
		}
		printf("%d\n",ans);
	}
}

然后进入第二题~:

B. Amr and The Large Array
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Amr has got a large array of size n. Amr doesn't like large arrays so he intends to make it smaller.

Amr doesn't care about anything in the array except the beauty of it. The beauty of the array is defined to be the maximum number of times that some number occurs in this array. He wants to choose the smallest subsegment of this array such that the beauty of it will be the same as the original array.

Help Amr by choosing the smallest subsegment possible.

Input

The first line contains one number n (1 ≤ n ≤ 105), the size of the array.

The second line contains n integers ai (1 ≤ ai ≤ 106), representing elements of the array.

Output

Output two integers l, r (1 ≤ l ≤ r ≤ n), the beginning and the end of the subsegment chosen respectively.

If there are several possible answers you may output any of them.


题意:

就是给你一个初始的数列,你需要选出一个连续的子数列,使得连续子数列中的最多元素的个数与原数列相等。


思路:

因为考虑到ai的限制性,仅有10^6的取值范围,因此我们用que[p].num表示p这个数出现的次数,que[p].st表示p这个数第一次出现的位置,que[p].ed表示p这个数最后一次出现的位置。之后的话只要以que[p].num作为第一关键字,que[p].ed-que[p].st 作为第二关键字进行排序即可。 但是非常不幸的是WA了一次,原因的话是que一开始直接开了10^6导致溢出。以后这种边界问题还是要引起相当重视的说Q+Q,之后贴出代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
	int st,ed,num;
	void init(){
		st=ed=-1;
		num=0;
	}
};
int cmp(node a,node b){
	if (a.num!=b.num)
		return (a.num>b.num);
	else if (a.ed-a.st!=b.ed-b.st)
		return (a.ed-a.st<b.ed-b.st);
	else
		return (a.st<b.st);
}
int n;
node que[1000005];
int p;
int main(){
	scanf("%d",&n);
	for (int i=0;i<=1000002;i++)
		que[i].init();
	for (int i=0;i<n;i++){
		scanf("%d",&p);
		if (que[p].num==0){
			que[p].st=que[p].ed=i;
			que[p].num++;
		}
		else{
			que[p].num++;
			que[p].ed=i;
		}
	}
	sort(que,que+1000002,cmp);
	printf("%d %d\n",que[0].st+1,que[0].ed+1);
}

然后进入第三题 (也是 当时做出来的最后一题了Q+Q  )

C. Amr and Chemistry
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Amr loves Chemistry, and specially doing experiments. He is preparing for a new interesting experiment.

Amr has n different types of chemicals. Each chemical i has an initial volume of ai liters. For this experiment, Amr has to mix all the chemicals together, but all the chemicals volumes must be equal first. So his task is to make all the chemicals volumes equal.

To do this, Amr can do two different kind of operations.

  • Choose some chemical i and double its current volume so the new volume will be 2ai
  • Choose some chemical i and divide its volume by two (integer division) so the new volume will be 

Suppose that each chemical is contained in a vessel of infinite volume. Now Amr wonders what is the minimum number of operations required to make all the chemicals volumes equal?

Input

The first line contains one number n (1 ≤ n ≤ 105), the number of chemicals.

The second line contains n space separated integers ai (1 ≤ ai ≤ 105), representing the initial volume of the i-th chemical in liters.

Output

Output one integer the minimum number of operations required to make all the chemicals volumes equal.


题意:

给你一些整数,要求通过对这些数通过*2或者整除2,来使得所有数都变为相同的某个数,每*2或者整除2一次,算一次操作。问最少可以通过多少次的操作达到目的?


思路:

乍看到这题的时候完全没有什么思路啊,只是感觉有一点点像倒水的那种题,但是那种题要推算的好麻烦Q+Q。但是这里说整除2和*2,这些操作不都是非常简单的位运算操作么?于是就朝着2进制的那个方向去思考。之后的一个思考方向就是如果整除2之后又*2导致的结果是什么?若最后一位是1,经过这样的操作之后就将变为0,但是我们也同时发现,我们并不能通过操作将某一位的0变为1。换而言之,加入在这n个数中的二进制某一位,有的是1,有的是0,那么最终的结果这一位一定是0,或者长度达不到。

那么从上述结论我们可以知道,对于这n个数,如果从二进制最高位开始有连续的p位完全相同(不是同为0 就是同为1),那么最终状态长度一定大于等于p,并且如果最终长度大于p的话,超过p的位数应该全部由0填充。

这样之后,我们的算法就是通过枚举位数,因为每一种位数,可以作为最优解的状态都是可以通过上一段得出的。然后计算每个数字到这个状态做需要最少的操作数是多少。下图将说明这个过程:

当对所有可能的解都进行枚举计算之后,返回极小值即可。复杂度为N(logN) 稍微自己感觉还是挺巧妙的XD 下面贴出代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
	int val[20];
	int len;
	void init(int now){
		memset(val,0,sizeof(val));
		len=0;
		int tmp=now;
		while (tmp!=0){
			val[len++]=tmp%2;
			tmp/=2;
		}
		for (int i=0;i<len/2;i++)
			swap(val[i],val[len-1-i]);
	}
};
node que[100005];
int n;
int maxn,mixn,stk;
bool fin_sum(int col){
	int ret=0;
	for (int i=0;i<n;i++)
		ret+=que[i].val[col];
	if (ret==0 || ret==n)
		return (true);
	return (false);
}
int cal(int sta,int id){
	int ret=0;
	if (que[id].len<=sta+1){
		int tag;
		int stp1=0;
		for (tag=stk+1;tag<que[id].len;tag++)
			if (que[id].val[tag]==1){
				stp1=(que[id].len-tag)*2;
				break;
			}
		return (stp1+sta+1-que[id].len);
	}
	else{
		int tag;
		int stp1=0;
		for (tag=stk+1;tag<=sta;tag++)
			if (que[id].val[tag]==1){
				stp1=(sta-tag+1)*2;
				break;
			}
		return (stp1+que[id].len-sta-1);
	}
	
}
int main(){
	mixn=50;
	maxn=-1;
	scanf("%d",&n);
	for (int i=0;i<n;i++){
		int p;
		scanf("%d",&p);
		que[i].init(p);
		mixn=min(mixn,que[i].len);
		maxn=max(maxn,que[i].len);
	}
	int sta=0;
	for (int i=0;i<mixn;i++)
		if (fin_sum(i))
			sta=i;
		else
			break;
	stk=sta;
	int step=-1;
	for (int i=sta;i<maxn;i++){
		int tmp=0;
		for (int j=0;j<n;j++)
			tmp+=cal(i,j);
		if (step==-1 || tmp<step)
			step=tmp;
	}
	printf("%d\n",step);

}

好了~后面的话 要把SRM 661 div 1的500、1000分题,以及这个div2的后面2题补了~要不然就真的丢在那里不会管了啦XD  去吃晚饭了Q+Q

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值