POI2014 Around the world
阿新 • • 發佈:2018-12-12
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;
}