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;
}

浙公网安备 33010602011771号