POJ 3484 Showstopper 前缀和思想+二分+输入处理

题目:

Showstopper
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 2457 Accepted: 739

Description

Data-mining huge data sets can be a painful and long lasting process if we are not aware of tiny patterns existing within those data sets.

One reputable company has recently discovered a tiny bug in their hardware video processing solution and they are trying to create software workaround. To achieve maximum performance they use their chips in pairs and all data objects in memory should have even number of references. Under certain circumstances this rule became violated and exactly one data object is referred by odd number of references. They are ready to launch product and this is the only showstopper they have. They need YOU to help them resolve this critical issue in most efficient way.

Can you help them?

Input

Input file consists from multiple data sets separated by one or more empty lines.

Each data set represents a sequence of 32-bit (positive) integers (references) which are stored in compressed way.

Each line of input set consists from three single space separated 32-bit (positive) integers X Y Z and they represent following sequence of references: X, X+Z, X+2*Z, X+3*Z, …, X+K*Z, …(while (X+K*Z)<=Y).

Your task is to data-mine input data and for each set determine weather data were corrupted, which reference is occurring odd number of times, and count that reference.

Output

For each input data set you should print to standard output new line of text with either “no corruption” (low case) or two integers separated by single space (first one is reference that occurs odd number of times and second one is count of that reference).

Sample Input

1 10 1
2 10 1

1 10 1
1 10 1

1 10 1
4 4 1
1 5 1
6 10 1

Sample Output

1 1
no corruption
4 3

题意:

多组数据。每组数据之间由若干空行分隔开。

对于一组数据,由若干行构成,每行有三个32位整数X,Y,Z, 用来表示一个数列:X, X+Z, X+2*Z, X+3*Z, …, X+K*Z, …(X+K*Z)<=Y)。比如 X = 3 , Y = 9 ,  Z = 2, 表示的数列为:3,5,7,9。

这样一组数据若有n行,就描述了n个数列。输入保证了这n个数列中出现的数字的次数至多有一个为奇数。 若存在这样一个数字出现奇数次,那么输出这个数字与它出现的次数,否则输出"no corruption".

思路:

由于保证了出现的所有数字中至多有一个为奇数。那么如果在k这个数字出现的次数为奇数,那么比k小的所有数字的次数前缀和都为偶数,比k大的所有数字次数前缀和均为奇数。我们可以根据这个性质假定答案进行二分求解,第一个使前缀和变为奇数的数字就是答案。

eg:样例3.  

1 10 1
4 4 1
1 5 1
6 10 1

数列1:1,2,3,4,5,6,7,8,9,10

数列2:4

数列3:1,2,3,4,5

数列4:6,7,8,9,10

数字   :1 , 2 ,3 , 4 ,5 , 6 , 7 , 8 , 9 ,10

次数   :2 , 2 , 2 ,3 ,2 , 2 , 2 , 2 , 2 , 2

前缀和:2 , 4 ,6 ,9 ,11,13,15,17,19,21

                                  ^^^^^^^^^^^^^^^^^^ 

最后要注意的细节就是这个恶心的输入了。由于每组数据行数未定,中间的空行未定,那么我只能通过有无空行来判断一组数据是否输入完了(x,y,z的值也就要由sscanf读入了)。这就会导致最后一组数据后面如果没有空行就无法输出,最终在循环外面又加了一次处理才能有了输出。。

代码:

#include<cstdio>  
#include<cstdlib>  
#include<cmath>  
#include<cstring>  
#include<iostream>  
#include<algorithm>  
#include<queue>  
#include<map>  
#include<stack> 
#include<set>
#define sd(x) scanf("%d",&x)
#define ss(x) scanf("%s",x)
#define sc(x) scanf("%c",&x)
#define sf(x) scanf("%f",&x)
#define slf(x) scanf("%lf",&x)
#define slld(x) scanf("%lld",&x)
#define me(x,b) memset(x,b,sizeof(x))
#define pd(d) printf("%d\n",d);
#define plld(d) printf("%lld\n",d);
#define eps 1.0E-8
// #define Reast1nPeace

typedef long long ll;

using namespace std;

const ll INF = 0x3f3f3f3f3f3f;

struct node{
	ll x,y,z;
	node(ll x,ll y,ll z){
		this->x = x , this->y = y , this->z = z;
	}
};

vector<node> v;

ll judge(ll m){  
	int len = v.size();
	ll sum = 0;
	for(int i = 0  ; i<len ; i++){
		if(m<v[i].x) continue;
		ll maxn = min(m,v[i].y);
		sum += (maxn-v[i].x)/v[i].z + 1; 
	}	
	return sum;
}

void solve(){
	ll l = 1 ; ll r = INF;
	ll ans = 0;
	while(l<=r){
		ll mid = (l+r)>>1;
		if(judge(mid)&1){
			ans = mid;
			r = mid-1;
		}
		else{
			l = mid+1;
		}
	}	
	if(ans == 0){
		cout<<"no corruption"<<endl;
	}
	else{
		cout<<ans<<" "<<judge(ans)-judge(ans-1)<<endl;
	}
}

int main(){
#ifdef Reast1nPeace
	freopen("in.txt", "r", stdin);
//	freopen("out.txt", "w", stdout);
#endif
	char str[20]; 
	bool flag = 0;
	while(gets(str)){
		if(strlen(str) == 0){
			if(flag){
				solve();
				flag = 0;	
				v.clear();
			} 
			continue;
		}
		flag = 1;
		ll x,y,z;
		sscanf(str,"%lld %lld %lld",&x,&y,&z);
		v.push_back(node(x,y,z));
	}
	if(flag)solve(); 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值