[POI2014]Around the world
题目大意:
一个环上有$n(n\le10^6)$个点,每个点之间的距离为$l_i(l_i\le10^9)$。有$m(m\le100)$架飞机,每架飞机单次最大航行距离为$d_i$。飞机只能在点上起飞、降落。问每架飞机是否可以飞完整个环,如果能,求中间最少停几次。
思路:
对于不能飞完的情况,若$d<\max\{l_i\}$则不能飞完。
如果可以飞完,则将环复制两遍将原问题转化为链上问题。用$sum[i]$表示$l_i$的前缀和,$f[i]$表示若最后一次停在$i$处,路上总共要停几次,$last[i]$表示若最后一次停在$i$处,起点最大能是多少。当$sum[i]-sum[j]\le d$时进行转移,$f[i]=f[j]+1,last[i]=last[j]$。当$sum[i]-sum[j]\ge\sum l_i$时,$f[i]$就是答案。显然当$i$单调增的时候,$j$也单调增,时间复杂度$O(mn)$。
1 #include<cstdio> 2 #include<cctype> 3 #include<algorithm> 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int N=1e6; 12 int sum[N<<1],f[N<<1],last[N<<1]; 13 int main() { 14 const int n=getint(),m=getint(); 15 int max=0; 16 for(register int i=0;i<n;i++) { 17 last[i]=i; 18 max=std::max(max,sum[i]=sum[i+n]=getint()); 19 } 20 for(register int i=1;i<n<<1;i++) { 21 sum[i]+=sum[i-1]; 22 } 23 for(register int i=0;i<m;i++) { 24 const int d=getint(); 25 if(d<max) { 26 puts("NIE"); 27 continue; 28 } 29 for(register int i=n,j=0;i<n<<1;i++) { 30 while(d<sum[i]-sum[j]) j++; 31 f[i]=f[j]+1; 32 last[i]=last[j]; 33 if(sum[i]-sum[last[i]]>=sum[n-1]) { 34 printf("%d\n",f[i]); 35 break; 36 } 37 } 38 } 39 return 0; 40 }