1. 程式人生 > >POI2014 Around the world

POI2014 Around the world

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;
}