修剪草坪 滑动窗口

  题目^o^

Pro
  在一年前赢得了小镇的最佳草坪比赛后,tw 变得很懒,再也没有修剪过草坪。现在,新一轮的最佳草坪比赛又开始了,tw 希望能够再次夺冠。
  然而,tw 的草坪非常脏乱,因此,tw 只能够让他的奶牛来完成这项工作。tw 有 N(1 <= N <= 100,000)只排成一排的奶牛,编号为 1...N。每只奶牛的效率是不同的,奶牛 i 的效率为 E_i(0 <= E_i <= 1,000,000,000)。
  靠近的奶牛们很熟悉,因此,如果 tw 安排超过 K 只连续的奶牛,那么,这些奶牛就会罢工去开派对:)。因此,现在 tw 需要你的帮助,计算 tw 可以得到的最大效率,并且该方案中没有连续的超过 K 只奶牛。


Input
  第一行:空格隔开的两个整数 N 和 K
  第二到 N+1 行:第 i+1 行有一个整数 E_i
Output
  一个值,表示 tw 可以得到的最大的效率值。


Sample Input
  5 2
  1
  2
  3
  4
  5
Sample Output
  12


Data Range
  30% 的数据, n<=100
  100% 的数据, n<=100000

随便说说版:

  刚刚才弄懂题目是什么意思qwq 

  看来还是没有融会贯通"要揣测出题人的意图"这句话

  或者说我语文太差了(这确实是一个事实)

正解:

  f[i] 表示安排前 i 个奶牛所获得的最大值 

  若i>k 那么 i-k ~ i 中至少有一个不选 

  不选的点为 j 即为断点 

  然后进入DP常规套路 枚举阶段 枚举断点 转移

  但是 

  这样子会超时 开O2也超时qwq 我们不得不想想优化

单调队列优化:

  发现我们枚举断点就是为了求出 f[j-1]-s[j] 的最大值 

  而 j 是一格一格往右移的 所以想到了滑动窗口   然后 没了

这里再讲一下滑动窗口:

  q[i]: 是单调队列 p[i]:是单调队列中 i 号元素在原来序列里的下标

  当要加入一个新的元素 y 的时候 先使队尾比 y 小的元素出队( tail-- ) 

  因为这些元素在有生之年已经没有机会成为最大的了

 (单调队列中的元素要成为最大元素,只有当比它大的元素都退休(滑出了窗口外)才行,现在来了一个比它大还比它年轻的元素,它自然没机会了)

   y 入队

  然后把滑出窗口外的元素弹出( head++ )  p 数组就是用于这一步

  就可以啦 

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 #define go(i,a,b) for(register int i=a;i<=b;i++)
 5 using namespace std;
 6 int read() //cannot read "-"
 7 {
 8     int x=0;char c=getchar();
 9     while(c<'0'||c>'9') c=getchar();
10     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
11     return x;
12 }
13 ll n,k,a[100010],s[100010],dp[100010];
14 int main()
15 {
16     n=read();k=read();
17     go(i,1,n) a[i]=read(),s[i]=s[i-1]+a[i];
18     dp[1]=a[1];
19     go(i,1,n)
20     {
21         if(i>k)
22         {
23             go(j,i-k,i)    dp[i]=max(dp[i],dp[j-1]+s[i]-s[j]);
24         }
25         else dp[i]=s[i];
26     }
27     printf("%lld",dp[n]);
28     return 0;
29 }
40~80分 Code
 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 #define go(i,a,b) for(register int i=a;i<=b;i++)
 5 using namespace std;
 6 int read() //cannot read "-"
 7 {
 8     int x=0;char c=getchar();
 9     while(c<'0'||c>'9') c=getchar();
10     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
11     return x;
12 }
13 ll n,k,head=1,tail=1,a[100010],s[100010],f[100010],q[100010*2],p[100010*2];
14 ll find(int x) //这里是单调队列优化 ! ! !
15 {
16     ll y=f[x-1]-s[x];
17     while(head<=tail&&q[tail]<=y) tail--;
18     q[++tail]=y; p[tail]=x;
19     while(p[head]<x-k) head++;
20     return q[head];
21 }
22 int main()
23 {
24     n=read();k=read();
25     go(i,1,n) a[i]=read(),s[i]=s[i-1]+a[i];
26     go(i,1,n)
27     {
28         f[i]=max(f[i],find(i)+s[i]);
29     }
30     printf("%lld",f[n]);
31     return 0;
32 }
AACC Code

猜你喜欢

转载自www.cnblogs.com/forward777/p/10321546.html