Problem B. Paragliding Google Kickstart Round D 2018

获取气球时只能向下45°滑行而不能向上滑。对于每一个Tower a和气球b,如果abs(p[a]-x[b])<=h[a]-y[b]则可以取到气球,小数据直接N^2枚举即可。

大数据必然是O(N)的,但开始也没发现什么类似单调性的规律去减少枚举。一直在纠结如果离气球b最近的tower a无法获得气球,而更远的tower c可以获得气球a该如何处理,这样很难减少枚举上限。><后来得知,这种情况下如果tower a无法取得气球b,tower a可以被tower b取代,因为如果从tower a可以获得某个气球x,从tower b一定可以获得那个气球x。(画个图就可以很明白滴看出来,tower a的区域包含于tower b的区域中)那么abs(p[a]-x[b])>h[a]-y[b],abs(p[c]-x[b])<=h[c]-y[b],可以得出tower a被tower c替代的条件是abs(p[a]-p[c])<=h[a]-h[c](画个图也可以看出来)

Then,可以先除去多余的Tower,再对于某一个balloons,找到距离其最近的两个Tower a, c,如果这两个Tower无法获取balloon,更远的Tower也不可能获取balloon,否则tower a, c就可以被更远的Tower替代。

除去多余的Tower:现将所有的Tower按照p[i]排序,遍历所有的tower i,如果tower i可以被new tower array尾部的tower替代,skip tower i,如果tower i可以替代new tower array尾部的Tower,将new tower array的Tower pop出来直到最后一个Tower不会被tower i替代为止。最后再将tower i append至new tower array尾部。因为Tower覆盖范围都是45°,不会出现排序后tower i不会替代tower i+1, 却会替代tower i+2的情况。

遇到的bugs:

计算p[i],h[i],x[i],y[i]时,公式是p[i]=linear(p[i-1],p[i-2])%M+1,所以不等于(linear(p[i-1]%M,p[i-2]%M)+1)%M...之前写习惯了,过了好久才发现o(╯□╰)o

在一个sorted数组中查找x,如果x不在数组里面,返回的mid可能是x插入位置的左边element下标,也可能是插入位置的右边element下标,所以mid-1,mid,mid+1都要check。用lower_bound()可以避免这个问题。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<ctype.h>
#include<map>
#include<time.h>
#include<set>
#include<bitset>
#include<sstream>
using namespace std;
//2018 round D Problem B. Paragliding
const int maxn=100010;
int T;
int N;
int K;
long long p[maxn];
long long x[maxn];
long long h[maxn];
long long y[maxn];
long long A[4];
long long B[4];
long long C[4];
long long M[4];
long long ans;
int sorted_tower[maxn];
int relative_tower[maxn];
bool cmp(int a,int b)
{
    return p[a]<p[b];
}
int check_relative(int a,int b)
{
    if(h[a]-h[b]>=abs(p[a]-p[b]))
    {
        return 0; // b is useless
    }
    else if(h[b]-h[a]>=abs(p[a]-p[b]))
    {
        return 1; // a is useless
    }
    else
    {
        return 2; //not relative
    }

}
bool get_ballon(int a,int b)//a is tower, b is ballon
{
//    cout<<"get ballon "<<a<<" "<<b<<" "<<h[a]<<" "<<p[a]<<" "<<y[b]<<" "<<x[b]<<endl;
    if(h[a]-y[b]>=abs(p[a]-x[b]))
    {
        return true;
    }
    return false;
}
int main()
{

    cin>>T;
    for(int ca=1;ca<=T;ca++)
    {
        
        memset(p,0,sizeof(p));
        memset(x,0,sizeof(x));
        memset(h,0,sizeof(h));
        memset(y,0,sizeof(y));
        memset(A,0,sizeof(A));
        memset(B,0,sizeof(B));
        memset(C,0,sizeof(C));
        memset(M,0,sizeof(M));
        memset(sorted_tower,0,sizeof(sorted_tower));
        memset(relative_tower,0,sizeof(relative_tower));
        ans=0;
        cin>>N>>K;
        cin>>p[0]>>p[1]>>A[0]>>B[0]>>C[0]>>M[0];
        cin>>h[0]>>h[1]>>A[1]>>B[1]>>C[1]>>M[1];
        cin>>x[0]>>x[1]>>A[2]>>B[2]>>C[2]>>M[2];
        cin>>y[0]>>y[1]>>A[3]>>B[3]>>C[3]>>M[3];
        for(int i=2;i<N;i++)
        {
            p[i]=(p[i-1]*A[0]+p[i-2]*B[0]+C[0])%M[0]+1;
            h[i]=(h[i-1]*A[1]+h[i-2]*B[1]+C[1])%M[1]+1;
//            p[i]=p[i-1]*A[0]%M[0]+p[i-2]*B[0]%M[0]+C[0]%M[0]+1;  without mod M at teh end, the value is different
//            p[i]%=M[0]; no need to take mod at the end
//            h[i]=h[i-1]*A[1]%M[1]+h[i-2]*B[1]%M[1]+C[1]%M[1]+1;
//            h[i]%=M[1];
        }
        for(int i=2;i<K;i++)
        {
            x[i]=(x[i-1]*A[2]+x[i-2]*B[2]+C[2])%M[2]+1;
            y[i]=(y[i-1]*A[3]+y[i-2]*B[3]+C[3])%M[3]+1;
//            x[i]=x[i-1]*A[2]%M[2]+x[i-2]*B[2]%M[2]+C[2]%M[2]+1;
//            x[i]%=M[2];
//            y[i]=y[i-1]*A[3]%M[3]+y[i-2]*B[3]%M[3]+C[3]%M[3]+1;
//            y[i]%=M[3];
        }
        for(int i=0;i<N;i++)
        {
            sorted_tower[i]=i;
        }
        sort(sorted_tower,sorted_tower+N,cmp);
//        for(int i=0;i<N;i++)
//        {
//            cout<<"("<<p[i]<<","<<h[i]<<") "<<endl;
//        }
//        cout<<endl;

//        for(int i=0;i<K;i++)
//        {
//            cout<<"("<<x[i]<<","<<y[i]<<") "<<endl;
//        }
//        cout<<endl;
        int cnt=0;
        for(int i=0;i<N;i++)
        {
            if(cnt==0)
            {
                relative_tower[cnt++]=sorted_tower[i];
                continue;
            }
            else
            {
                int check=check_relative(sorted_tower[i],relative_tower[cnt-1]);
                if(check==0)// need to push new tower i at the end
                {
                    while(cnt>0)
                    {
                        if(check_relative(sorted_tower[i],relative_tower[cnt-1])==2)
                        {
                            break;
                        }
                        cnt--;
                    }
                }
                else if(check==1)
                {
                    continue;
                }
                relative_tower[cnt++]=sorted_tower[i];
            }
        }
//        int cnt=getRelevantTowers();
//        for(int i=0;i<N;i++)
//        {
//            cout<<sorted_tower[i]<<" ";
//        }
//        cout<<endl;
//        for(int i=0;i<cnt;i++)
//        {
//            cout<<p[relative_tower[i]]<<" ";
//        }
//        cout<<endl;
//        cout<<cnt<<endl;
        for(int i=0;i<K;i++)
        {
            int left=0;
            int right=cnt-1;
            int mid=(left+right)/2;
            bool flg=false;
            while(left<=right)
            {
                mid=(left+right)/2;
                int tower=relative_tower[mid];
                if(p[tower]<x[i])
                {
                    left=mid+1;
                }
                else
                {
                    right=mid-1;
                }
            }
//            cout<<"mid "<<relative_tower[mid]<<endl;
//            if(mid==0)// only consider left most tower
//            {
//                if(get_ballon(relative_tower[mid],i)==true)
//                {
//                    flg=true;
//                }
//            }
//            else

            if(get_ballon(relative_tower[mid],i)==true)
            {
                flg=true;
//                  cout<<"here2"<<endl;
            }
                
            else if(mid+1<cnt&&get_ballon(relative_tower[mid+1],i)==true)
            {
                flg=true;
//                   cout<<"here3"<<endl;
            }
            else if(mid>0&&get_ballon(relative_tower[mid-1],i)==true)
            {
                flg=true;
                //                   cout<<"here4"<<endl;
            }


            if(flg==true)
            {
                ans++;
            }
        }
        
        printf("Case #%d: %lld\n",ca,ans);
        
        
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值