Luogu P4403 [BJWC2008]秦腾与教学评估【二分答案】By cellur925

题目传送门

这道题:真·凉心出题人。

二分答案,个人感觉其实并不只适用于有明显的“最大值最小/最小值最大”条件的题目,其实也可以称它为一种“优化的暴力”。这题就是最好的例子。

我们肯定可以先想出朴素的算法:把每个点的答案都算出,但是平方级别的复杂度,铁定超时。

我们考虑用二分优化。这道题的二分其实挺难看出的:因为题目约束奇数人数的点要有也只有一个,也就是说其他有人的点上人数一定为偶数。显然偶数+偶数=偶数,如果没有奇数出现,那么统计的人数和都是偶数。

我们可以从这个性质出发。二分位置\(i\),但是二分的不是最终的结果而是一个约束的范围。再具体地说,如果\([1,mid]\)中的人数是奇数那么答案肯定在这个区间中,使\(r=mid\),否则在右边的区间,即使\(l=mid+1\)

因此我们只要统计人数就行了==。

但是因为一些蜜汁原因,第一次交竟然\(T\)了。反正在洛谷&&脖子\(oj\)上捣鼓了半天也是奥妙重重。不过这个题提供的思路还是很棒的。

奉上阉割版代码。

#include<cstdio>
#include<algorithm>
#define maxn 200090
 
using namespace std;
typedef long long ll;
 
int T,n,ans;
int s[maxn],e[maxn],d[maxn];
 
int check(int x)
{
    int cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(s[i]>x) continue;
        cnt+=(ll)(min(x,e[i])-s[i])/d[i]+1;
    }
    return cnt;
}
 
void re(int &x)
{
    x=0;
    char ch=getchar();
    bool flag=false;
    while(ch<'0'||ch>'9') flag|=(ch=='-'),ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    x=flag ? -x : x;
}
 
int main()
{
    re(T);
    while(T--)
    {
        re(n);
        for(int i=1;i<=n;i++)
            re(s[i]),re(e[i]),re(d[i]);
        ll l=0,r=2147483647;
        while(l<=r)
        {
            ll mid=(l+r)>>1;
            if(check(mid)&1) r=mid-1,ans=mid;
            else l=mid+1;
        }
        if(!ans) printf("Poor QIN Teng:(\n");
        else printf("%lld %d\n",l,check(l)-check(l-1));
        l=1,r=0,ans=0;
    }
    return 0;
}
posted @ 2018-11-03 17:16  cellur925&Chemist  阅读(320)  评论(0编辑  收藏  举报