https://vjudge.net/contest/184514#problem/L
题意:
排成一行的一堆牌,每堆牌都有一定数量的牌,然后每堆牌对应有一个惩罚值。一开始所有的牌都是正面向下的,并且在游戏开始之前可以把第一堆牌移到最后,这个操作可以进行若干次。在那之后,一个人开始依次拿起一堆牌,并且把它们全部正面朝上,之后需要把某些牌翻转到正面向下,翻转的数量就是这堆牌的惩罚值,之后把正面向上的牌翻转加到下一堆进行操作。当遇到当前的正面向上的牌小于当前的牌的惩罚值的时候,游戏结束,可以得到这堆牌以及之前的所有牌。
问需要挪多少堆到后面可以得到最大数量的牌。
思路:
一开始被题解误导,wa了6发。首先这题由于要挪到后面,而且有顺序,所以很自然的想到复制一份加到后面,形成一个环,这样方便许多。之后我们设置3个变量,一个表示当前取得的牌数num,一个表示当前减去惩罚值之后剩下的牌sum,一个记录当前取得堆的数量cnt。当cnt >= n的时候,就说明我们可以取到全部,也就是取到最多的了,记录位置并跳出。当sum < 0 的时候,就说明不能再取了,此时就更新num的值并记录此时的位置,将cnt和sum重置为0.循环完之后所求的num就是最大值。
当我们记录的位置ans最后要减去n,因为我们是讲题中所给的线拼成了一个环,所以位置会有偏移。
代码:
1 #include <stdio.h>
2 #include <string.h>
3
4 int a[2000005];
5 int b[2000005];
6
7 int main()
8 {
9 int n;
10
11 while (scanf("%d",&n) != EOF)
12 {
13 for (int i = 1;i <= n;i++)
14 {
15 scanf("%d",&a[i]);
16 a[i+n] = a[i];
17 }
18
19 for (int i = 1;i <= n;i++)
20 {
21 scanf("%d",&b[i]);
22 b[i+n] = b[i];
23 }
24
25 long long pre = 0;
26 long long sum = 0;
27 long long num = 0;
28 long long maxx = -1e12;
29 int ans = 0;
30 int cnt = 0;
31
32 for (int i = 1;i < 2 * n;i++)
33 {
34 num += a[i];
35
36 sum = (pre + a[i] - b[i]);
37
38
39 if (sum >= 0)
40 {
41 cnt++;
42 pre = sum;
43 }
44 else
45 {
46 if (num > maxx)
47 {
48 maxx = num;
49 ans = i;
50 }
51
52 pre = 0;
53 cnt = 0;
54 }
55
56 if (cnt >= n)
57 {
58 ans = i;
59 break;
60 }
61 }
62
63 if (ans == n) printf("%d
",0);
64 else printf("%d
",ans - n);
65 }
66
67
68 return 0;
69 }