获取气球时只能向下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;
}