[日常摸鱼]bzoj1271秦腾与教学评估-二分
https://darkbzoj.tk/problem/1271
题意:一个无限长的数列,下标从1开始,开始全为0,现在给\(n\)个操作\((s_i,e_i,d_i)\)表示让\(s_i,s_i+d_i,s_i+2d_i,\dots,s_i+kd_i(s_i+kd_i\leq e_i \&s_i+(k+1)d_i>e_i)\)这些位置+1,同时保证最后至多有一个位置的值是奇数,回答是否存在这样的位置,如果存在则输出位置。
题解:至多只有一个位置非常关键,虽然原数列可能是:偶…偶奇偶…,但是考虑前缀和的话就会变成:偶…偶奇奇…,好的有二分性质了…
现在就只要考虑给一个位置\(x\)怎么快速求对应的前缀和就行,发现也很简单…如果不考虑\(e_i\)这个东西,那第\(i\)个操作的贡献就直接是\(\begin{aligned}1+\lfloor\frac{x-s_i}{d_i}\rfloor\end{aligned}\),有\(e_i\)的话\(x\)变成\(min(x,e_i)\)就行啦…于是就能\(O(n\log m)\)地做了,\(m\)是值域。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;
const int N=2e5+5;
const int M=(~0u>>1);
int n,T;
int S[N],D[N],E[N];
ll check(int x)
{
ll res=0;
rep(i,1,n)if(x>=S[i])
{
if(x>=E[i])res+=1ll*(1+(E[i]-S[i])/D[i]);
else res+=1ll*(1+(x-S[i])/D[i]);
}
return res;
}
int main()
{
scanf("%d",&T);
rep(tc,1,T)
{
scanf("%d",&n);
rep(i,1,n)scanf("%d%d%d",&S[i],&E[i],&D[i]);
ll l=0,r=M;
while(r>l)
{
ll mid=(l+r)>>1;
ll t=check(mid);
if(t&1ll)r=mid;
else l=mid+1;
}
ll t=check(l);
if(t&1ll)printf("%d %lld\n",l,check(l)-check(l-1));
else printf("Poor QIN Teng:(\n");
}
return 0;
}