P4403 [BJWC2008]秦腾与教学评估

哼哼啊啊啊啊啊啊啊啊啊啊啊

我在洛谷上找期望题找到了这玩意儿好吧,这玩意儿期望根本不可做好吧。

形式化题意:

在一条线段上有许多点。这些点可以用\(3n\)个整数来表示,每行的三个整数分别为\(S_i,E_i,D_i\),表示有许多个点在\(S, S + D, S + 2D, …, S + KD (K \in Z, S + KD ≤ E, S + (K + 1)D > E)\)位置。求在这一条线段上是否有一个点上的点的个数为奇数,保证解最多只有一个,若无解则输出$ \ Poor QIN Teng:( \ $,否则就输出那个唯一的点个个数以及有多少个点在它的上面。(摘自题解)

思路:

考虑二分。

我们如果只对单个位置考虑它是否有奇数个点,就会发现这样去找实际上是没有单调性的,不能用二分来解决。

那么既然它最多只会有一个奇数个点的位置,那么我们就思考用点数前缀和来入手,发现如果\(sum_i\)为奇数,那么这个位置一定在前面,如果为偶数,就不断往后二分,直至找到或者确定无解为止。如果知道了一个点的位置,那么计算这个位置的点数前缀和其实是比较好写的,\(O(n)\) \(A\)上即可。

哼哼啊啊啊啊啊啊啊啊啊啊啊(痛苦

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=201000;
int n,T,maxx;
int S[maxn],E[maxn],D[maxn];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') w=-1;
		ch=getchar(); 
	} 
	while(ch>='0'&&ch<='9'){
		s=(s<<3)+(s<<1)+(ch^48);
		ch=getchar();
	}
	return s*w;
}
inline int calc(int val){
	int sum=0;
	for(int i=1;i<=n;++i){
		int p=val;
		if(val<S[i]) continue;
		if(val>E[i]) p=E[i];
		p-=S[i];
		sum+=p/D[i]+1;
	}
	return sum;
}
inline int pcalc(int val){
	int sum=0;
	for(int i=1;i<=n;++i){
		if(val<S[i]) continue;
		if(val>E[i]) continue;
		if((val-S[i])%D[i]==0) sum++;
		//printf("%lld %lld %lld\n",sum,S[i],D[i]);
	}
	return sum;
}
signed main(){
	T=read();
	while(T--){
		n=read();maxx=-1;
		for(int i=1;i<=n;++i){
			S[i]=read();
			E[i]=read();
			D[i]=read();
			maxx=max(E[i],maxx);
		}
		int l=0,r=maxx,ans=-1;
		while(l<=r){
			int mid=(l+r)>>1;
			if(calc(mid)&1){
				ans=mid;
				r=mid-1;
			}else l=mid+1;
		}
		if(ans==-1) printf("Poor QIN Teng:(\n");
		else printf("%lld %lld\n",ans,pcalc(ans));
	}
	return 0;
} 
posted @ 2022-08-10 16:47  Broken_Eclipse  阅读(29)  评论(0)    收藏  举报

Loading