Around the world
POI2014
从未见过如此无耻的题目——既卡时间又卡空间
题意
1.在一个圆上有n个飞机场
2.L[i]是第i个与第i+1个机场之间的距离
(L[n]是第n个和第1个之间的距离)
3.有s个询问,每个询问有一个d[i]
4.对于每个询问:起点任选,每次飞行的距离不能超过d[i],绕这个圆一圈至少要飞多少次
解
方案1(并查集)
1.从左往右,每个点所能到达的最远是单调不降的
2.断环成链,将链延长到两倍
3.预处理出每个点到达的最远点(尺取)
4.枚举起点x
5.求最少几次可以跳到>=x+n的点
用并查集往上跳,找到第一个par[x]>=i+n的点,然后把经过的点全部指向par[x]
因为从左往右,每个点要跳到的点也是单调后移的,即这些点只会往后面合并,这就保存并查集的合并均摊是O(n)的
具体代码
//因为被卡了内存,于是去掉了万能头文件
//因为被卡了时间,于是加了O3优化
#pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
using namespace std;
const int M=1000005;
int n,S,D;
int dis[M],par[M*2],stk[M],val[M*2],top;
int Dis(int x) {
if(x<=n)return dis[x];
return dis[x-n];
}
void solve() {
int L=1,R=1;
int sum=0;
for(int i=1; i<=n+n; i++)par[i]=i,val[i]=0;
while(L<=n+n) {
while(R<=n+n&&sum+Dis(R)<=D) {
sum+=Dis(R);
R++;
}
par[L]=R;
if(par[L]!=L)val[L]=1;
sum-=Dis(L);
L++;
}
int ans=1e9;
for(int i=1; i<=n; i++) {
int x=i;
top=0;
bool flag=1;
while(1) {
if(par[x]==x) {
flag=0;
break;
}
stk[++top]=x;
if(par[x]>=i+n)break;
x=par[x];
}
while(top>1) {
val[stk[top-1]]+=val[stk[top]];
par[stk[top-1]]=par[x];
top--;
}
if(flag)ans=min(ans,val[i]);
}
if(ans==1e9)printf("NIE\n");
else printf("%d\n",ans);
}
int main() {
scanf("%d %d",&n,&S);
int mx=0;
for(int i=1; i<=n; i++) {
scanf("%d",&dis[i]);
mx=max(dis[i],mx);
}
for(int i=1; i<=S; i++) {
scanf("%d",&D);
if(D<mx)printf("NIE\n");
else solve();
}
return 0;
}
方案2(贪心)
1.先断环成链,计算前缀和
2.依次找n~2*n的点向前最远可以到哪里
一遍扫过去,while(dis[i]-dis[pos]>D)pos++,因为越后面,向前的最远点必然也后移
3.每次每次把i点向前并到pre[pos]里,并且贡献+1,
4.找到第一个i-pre[i]>=n即可
具体代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int M=1000005;
int n,S,D;
int dis[M*2],pre[M*2],val[M*2];
void solve() {
for(int i=1;i<=n*2;i++)val[i]=0,pre[i]=i;
int pos=0;
for(int i=n;i<=n*2;i++){
while(dis[i]-dis[pos]>D)pos++;
pre[i]=pre[pos];
val[i]=val[pos]+1;
if(i-pre[i]>=n){
printf("%d\n",val[i]);
return;
}
}
}
int main() {
scanf("%d %d",&n,&S);
int mx=0;
for(int i=1; i<=n; i++) {
scanf("%d",&dis[i]);
mx=max(dis[i],mx);
dis[i+n]=dis[i];
}
for(int i=1;i<=n*2;i++){
dis[i]+=dis[i-1];
}
for(int i=1; i<=S; i++) {
scanf("%d",&D);
if(D<mx)printf("NIE\n");
else solve();
}
return 0;
}