HDU4768 Flyer 二分|异或的性质|暴力

52 篇文章 0 订阅
21 篇文章 0 订阅

题目链接:HDU4768

测试一下,能否显示图片

题目大意:如果有学生拿了奇数张传单,输出其ID以及传单数量,否则输出DC Qiang is unhappy。

代码来自:队友@Vectorhr + 大佬的队伍@bhza8987510 (WHU-潘俊霖)

下面提供两种做法,代码里注释写的很清楚,直接看代码就好啦

AC代码1:

/*
2017年8月25日11:15:13
HDU4768
异或的性质 
AC 
*/ 
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
using namespace std;
const int maxn=2e5+5;
typedef long long ll;
ll a[maxn],b[maxn],c[maxn];

int main(){
	ll n,res,sum;
	while(~scanf("%lld",&n)){
		res=sum=0;
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(c,0,sizeof(c));
		for(ll i=1;i<=n;i++){
			scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
		}
		for(ll i=1;i<=n;i++){
			for(ll j=a[i];j<=b[i];j+=c[i]){
			//	printf("%lld^%lld= %lld\n",j,res,res^j);
			/*
			这里用到了异或的性质,同一个数异或偶数次结果为0,
			异或奇数次为其本身,所以如果res为0,那么每个数都出现了偶数次,
			否则res就等于出现了奇数次的那个人的标号。
			很巧妙!记得开Long long 可能会爆 
			*/ 
				res^=j;
			}
		}
		if(res){
			for(ll i=1;i<=n;i++){
				/*统计每一组a,b,c对这个人的贡献,每一组最多贡献1*/ 
				if(res>=a[i]&&res<=b[i]&&((res-a[i])%c[i])==0) ++sum;
			}
			//printf("res=%lld",res);
			printf("%lld %lld\n",res,sum);
		}
		else{
			printf("DC Qiang is unhappy.\n");
		}
		
	}
	return 0;
}


AC代码2:

/*
2017年8月25日11:19:04
HDU4758
二分查找
AC 
*/ 
#include <iostream>
#include <map>
#include <set>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
using namespace std;
const int maxn=2e4+10;
typedef long long ll;
const ll inf=0x3f3f3f3f;
ll a[maxn],b[maxn],c[maxn];
ll tot;

int main(){
	int n;
	while(~scanf("%d",&n)){
		tot=0;
		ll mx=-inf,mi=inf;
		for(int i=1;i<=n;i++){
			scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
			mx=max(b[i],mx);
			mi=min(a[i],mi);
			tot+=(b[i]-a[i])/c[i]+1;//对每一组a,b,c贡献的传单数量求和 
		}
		if((tot&1)==0) printf("DC Qiang is unhappy.\n");
		else{
			//利用二分,求出使得传单数量为奇数的那个人的标号 
			ll mid=(mx+mi)>>1;
			ll r=mx;
			ll l=mi;
			while(l<r){
				tot=0;
				for(int i=1;i<=n;i++){
					if(mid<a[i]) continue;
					else{
						tot+=(min(mid,b[i])-a[i])/c[i]+1;
					}
				}
				if((tot&1)==0) l=mid+1;
				else r=mid;
				mid=(l+r)>>1;
			}
			ll ans=0;
			for(int i=1;i<=n;i++){
				/*统计每一组a,b,c对这个人的贡献,每一组最多贡献1*/ 
				if(r>=a[i]&&r<=b[i]&&((r-a[i])%c[i]==0)) ans++;
			}
			printf("%lld %lld\n",r,ans);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值