https://www.luogu.com.cn/problem/P5017
这个题用了很多奇怪的思想
也可能是我太孤陋寡闻了)
题解:
抽象化题目:
大概就是一段数轴,表示时间,令每个同学到来的时间为数轴上的一个点,
在某一时间安排车辆就相当于在某个点取一段左开右闭区间,每段长度>=m
等车时间等于该点距右方闭合处的距离
这个线性dp方程式就出来了
么的办法,不会编辑公式)
在递推 fi 之前需要预处理仅在当前时间安排一辆车的损耗时间
即
然后我们就想到了前缀和优化——降低时间复杂度
定义了sum[ ] cnt[ ]两个数组,分别为前缀和、前缀点数目
于是改写一下dp
O ( t2)
然后用这个粗糙的算法得到了50……
简单优化一下
原先 j ∈( - ∞ , i -m )可以修改为( i - 2 * m , i - m )
O(mt)
因为如果间隔超过2m,就多出了一趟汽车往返的时间刚好满足减少等待时间
然后就混了个70
再优化一下下
可以见得假如在( i - m , i ]没有任何点
cnt[ i ] 与 cnt[ i - m ]相当
那么直接将 f [ i ] = f [ i - m ]
然后我们就AC了
时间复杂度优化为 O(nm2 + t )
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 int sum[4000005],cnt[4000005],f[4000005]; 7 8 int main() 9 { 10 ios_base::sync_with_stdio(false); 11 cout.tie(NULL); 12 int n,m; 13 cin>>n>>m; 14 int x; 15 int aux=1e7; 16 int maxn=0; 17 for(register int i=1;i<=n;i++) 18 { 19 cin>>x;maxn=max(maxn,x); 20 cnt[x]++;sum[x]+=x; 21 } 22 for(register int i=1;i<maxn+m;i++) 23 cnt[i]+=cnt[i-1],sum[i]+=sum[i-1]; 24 25 for(register int i=0;i<maxn+m;i++){ 26 if(i>=m && cnt[i-m] == cnt[i]) {f[i]=f[i-m];continue;} 27 f[i] = cnt[i] * i - sum[i]; 28 for(register int j=(i-m-m+1>0)?i-m-m+1:0;j<=i-m;j++) 29 { 30 // if(i-m-m+1 < 0) j=0; 31 f[i]=min(f[i],f[j] + ( cnt[i]-cnt[j]) * i - (sum[i] - sum[j]) ); 32 } 33 } 34 35 for(register int i=maxn;i<maxn+m;i++) aux=min(aux , f[i]); 36 cout<<aux; 37 }
-end-