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

 

posted @ 2018-03-30 10:35  skylee03  阅读(122)  评论(0编辑  收藏  举报