Problem C. Watson and Intervals Google APAC 2017 University Test Round B

这一题先将区间转化成左闭又开的形式[L,R),然后将所有的区间左右端点按照从小大大排序。从左往右扫一遍,遇到区间左端点+1,区间右端点-1,就得到每个点被区间覆盖的次数。如果一个点是多个区间的端点,只有最右侧的覆盖次数才是最终的结果。例如区间[1,3)、[1,4)中,1就被覆盖了两次。所以在sorted array中,右侧的1的覆盖次数才是正确的。

之后可以通过map记录覆盖次数=1的端点贡献的区间内点的个数。eg., [a1,a2,a3]中,如果a1的覆盖次数为1,那么a1的贡献就是a2-a1。

之后从右向左扫描,记录后缀和(覆盖次数=1的点的个数)。因为相同的点只有最右侧的值才是正确的,所以第一次 扫描到某个点才计算其后缀和。

之后对于任意一个区间,就可以通过后缀和在O(1*log n)内(map获取元素值是log n,后缀和相减是O(1))求出该区间内覆盖次数=1的点的个数了。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>

using namespace std;

//2017 RoundB Problem C. Watson and Intervals

const int maxn=500010;
int T;
int N;
int M;
int L;
int R;
int A;
int B;
int C1;
int C2;
class node
{
public:
    int val;
    int pointidx;
    bool start;
    int cover;
public:
    node()
    {
        val=0;
        pointidx=0;
        start=false;
        cover=0;
    }
    node(int v,int p,bool s)
    {
        val=v;
        pointidx=p;
        start=s;
        cover=0;
    }
};
bool cmp(node a,node b)
{
    return a.val<b.val;
}
pair<int,int>P[maxn];
node Point[maxn*2];
map<int,int>mplen;//point i to point i-1 for mplen[i]
map<int,int>mppresum;//suffix sum
int totalcover;
int main()
{
    //freopen("input.txt","r",stdin);
    freopen("C-large-practice.in","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        int cnt=0;
        scanf("%d %d %d %d %d %d %d %d",&N,&L,&R,&A,&B,&C1,&C2,&M);
//        if(ca!=15)
//        {
//            continue;
//            printf("%d %d %d %d %d %d %d %d\n",N,L,R,A,B,C1,C2,M);
//            return 0;
//        }
//        continue;
        memset(P,0,sizeof(P));
        memset(Point,0,sizeof(Point));
        mplen.clear();
        mppresum.clear();
        totalcover=0;
        P[0]=make_pair(L,R);
        Point[cnt++]=node(L,0,true);
        Point[cnt++]=node(R+1,0,false);
        for(int i=1;i<N;i++)
        {
            int x=((long long)P[i-1].first*A+(long long)P[i-1].second*B+C1)%M;
            int y=((long long)P[i-1].second*A+(long long)P[i-1].first*B+C2)%M;
            int l=min(x,y);
            int r=max(x,y);
            P[i]=make_pair(x,y);//what if two start points are the same?
            Point[cnt++]=node(l,i,true);//cover the points in [l,r)
            Point[cnt++]=node(r+1,i,false);//remove nodes with same [l,r]
        }
        sort(Point,Point+cnt,cmp);
//        for(int i=0;i<cnt;i++)
//        {
//            cout<<Point[i].val<<endl;//" "<<Point[i].pointidx<<" "<<Point[i].start<<endl;
//        }
//        cout<<"==="<<endl;
        Point[0].cover=1;
        for(int i=1;i<cnt;i++)
        {
            if(Point[i].start==true)
            {
                Point[i].cover=Point[i-1].cover+1;
            }
            else
            {
                Point[i].cover=Point[i-1].cover-1;
            }
        }
//        for(int i=0;i<cnt;i++)
//        {
//            cout<<Point[i].val<<" "<<Point[i].pointidx<<" "<<(Point[i].start?"T":"F")<<" "<<Point[i].cover<<" ED"<<endl;
//        }
        for(int i=0;i<cnt;i++)
        {
            if(Point[i].cover>0)
            {
                totalcover+=Point[i+1].val-Point[i].val;//include [i,i+1]
            }
        }
        //cout<<totalcover<<endl;
        for(int i=0;i<cnt;i++)
        {
            if(Point[i].cover==1)//&&Point[i].start==true
            {
                mplen[Point[i].val]=Point[i+1].val-Point[i].val;
//                cout<<Point[i].val<<" "<<mplen[Point[i].val]<<endl;
            }
        }
        mppresum[Point[cnt-1].val]=mplen[Point[cnt-1].val];
        for(int i=cnt-2;i>=0;i--)
        {
            if(mppresum.find(Point[i].val)==mppresum.end())
            {
                mppresum[Point[i].val]=mppresum[Point[i+1].val]+mplen[Point[i].val];
                //cout<<Point[i].val<<" "<<mppresum[Point[i].val]<<" "<<mppresum[Point[i+1].val]<<" "<<mplen[Point[i].val]<<endl;
            }
        }
        int maxlen=0;
        for(int i=0;i<N;i++)
        {
            int l=min(P[i].first,P[i].second);
            int r=max(P[i].first,P[i].second)+1;
//            WA is caused due to add 1 first then take max
//            int l=min(P[i].first,P[i].second+1);
//            int r=max(P[i].first,P[i].second+1);
            int tmp=mppresum[l]-mppresum[r];
//            if(i==677) cout<<l<<" p "<<r<<endl;
//            cout<<l<<" "<<r<<" "<<tmp<<endl;
            maxlen=max(maxlen,tmp);
        }
        printf("Case #%d: %d\n",ca,totalcover-maxlen);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值