Codeforces Round #466 (Div. 2)
比赛时没想出来...赛后听大佬说了说感觉其实很简单嘛...
这题算是个结论题吧,我们可以发现分得段的长度要么是c要么是1,于是就用单调队列维护前c个数的最小值更新即可。
为什么要么是c要么是1呢?感性的理解一下,如果一段长度为c+1的,那么将其拆成c和1的话,一定不会更差,因为如果最小值在中间的话,值是一样的,在两边的话值会更优。对于c+2也是一样的道理,在中间没影响,在两端的2个的话答案会更优....
其他都是同理。
1 #include<bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 const int inf=1e5+10; 5 int n,c; 6 int a[inf]; 7 LL f[inf],s[inf]; 8 struct ghb{ 9 int id,val; 10 }que[inf]; 11 int l,r; 12 int main() 13 { 14 scanf("%d%d",&n,&c); 15 for(int i=1;i<=n;i++)scanf("%d",&a[i]),s[i]=s[i-1]+a[i]; 16 l=1;r=0; 17 for(int i=1;i<=n;i++){ 18 f[i]=f[i-1]+a[i]; 19 while(l<=r&&que[l].id<=i-c)l++; 20 while(l<=r&&a[i]<que[r].val)r--; 21 que[++r]=(ghb){i,a[i]}; 22 if(i>=c){ 23 f[i]=min(f[i-c]+s[i]-s[i-c]-que[l].val,f[i]); 24 } 25 } 26 printf("%lld\n",f[n]); 27 return 0; 28 }