码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round #466 (Div. 2) Problem A - E

时间:2018-02-25 15:54:23      阅读:233      评论:0      收藏:0      [点我收藏+]

标签:特殊   number   amp   ima   ide   add   单调队列   tag   enum   

小结

  这场比赛和同学一起打。本来应该是很开心的事情,结果留下好多遗憾。

  第一个遗憾是没能在20分钟内消灭A、B题。然后分数就不是很可观。

  我第一次交B题都20多分钟了。然后朋友们说我的贪心有锅,然后我就真信了。

  于是我就重新写了个贪心交一发。好玩的是,考完我重新交了下B题之前的程序A了。

  C、D题做得比较快,因为比较简单。(想吐槽一句。为什么cf div 2前4题只有普及组难度了?)

  E题是最好玩的。读完题,写出了dp式子,我觉得会和按$c$分段有关,然后ZJC表示我在搞笑,我怎么又信了?

  然后思路就被带偏了。然后写暴力dp打表找决策单调性,然而写挂了,样例都挂,然后就弃疗了。

  比赛最后10分钟,红太阳QJX表示她A掉了E题,转移不是长度为1就是$c$。剩下的人全部在试图hack这个做法。(为什这个时候我就不信了qwq)

  看到Doggu的一个朋友1小时A掉5道题,最后一题直接弃坑。我的内心是崩溃的。

  主要还是A、B题做得太慢了吧。真正有意思的题目到后面都没时间思考。

  综上所述,还是我太菜了。

Codeforces 940A Points on the line

题目大意

  定义一个可重集的距离是它中间最大的两个数之间的差,特殊地,只有一个元素的可重集的距离为0。

  给定一个可重集,问最少删掉多少个数使得它的距离小于等于d。

  排序后单调指针扫,或者直接开桶计数。

Code

技术分享图片
 1 /**
 2  * Codeforces
 3  * Problem#940A
 4  * Accepted
 5  * Time: 15ms
 6  * Memory: 2000k
 7  */ 
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11 
12 int n, d;
13 int res;
14 int* ar;
15 
16 inline void init() {
17     scanf("%d%d", &n, &d);
18     ar = new int[(n + 1)];
19     for (int i = 1; i <= n; i++)
20         scanf("%d", ar + i);
21 } 
22 
23 inline void solve() {
24     sort (ar + 1, ar + n + 1);
25     int r = 1;
26     res = n - 1;
27     for (int i = 1; i <= n; i++) {
28         while (r < n && ar[r + 1] - ar[i] <= d) r++;
29         res = min(res, i + (n - r) - 1);
30     }
31     printf("%d", res);
32 }
33 
34 int main() {
35     init();
36     solve();
37     return 0;
38 }
Problem A

Codeforces 940B Our Tanya is Crying Out Loud

题目大意

  给定一个数$n$和$k$。你有两个操作可以进行

  1. 将$n$减去1,花费$a$。
  2. 当$n$是$k$的倍数的时候,将$n$除以$k$,花费$b$。

  问将$n$变为1的最小花费

  当$n$为$k$的倍数的时候,比较直接除和直接减到$\frac{n}{k}$的花费,如果前者更优就除,否则直接减到1。

  当$n$不为$k$的倍数的时候,直接减到$\left \lfloor\frac{n}{k}  \right \rfloor k$。

  考虑这么做的正确性,唯一这么做的问题是会不会存在多减几次使答案更优的情况。

  答案是不会的,因为先除可以避免使用多次的减法(除更优的情况下)。

  举个例子来说明,将$k^{2} + k$变为1。

  方案1:$k ^ {2} + k \rightarrow k + 1 \rightarrow k \rightarrow 1$

  方案2:$k ^ {2} + k \rightarrow k^{2} \rightarrow k \rightarrow 1$

  方案1使用了1次加法和2次除法,而方案二使用了$k$次加法和2次除法。

Code

技术分享图片
 1 /**
 2  * Codeforces
 3  * Problem#940B
 4  * Accepted
 5  * Time: 30ms
 6  * Memory: 2000k
 7  */ 
 8 #include <bits/stdc++.h>
 9 #ifndef WIN32
10 #define Auto "%lld"
11 #else
12 #define Auto "%I64d"
13 #endif
14 using namespace std;
15 
16 #define ll long long
17 
18 ll n, k, a, b, res = 0;
19 
20 inline void init() {
21     scanf(Auto""Auto""Auto""Auto, &n, &k, &a, &b);
22 }
23 
24 inline void solve() {
25     if (k == 1) {
26         res = (n - 1) * a;
27     } else {
28         while (n != 1) {
29             if (n < k) {
30                 res += (n - 1) * a;
31                 break;    
32             } else {
33                 res += min((n % k) * a + b, (n - n / k) * a);
34                 n /= k;
35             }
36         }
37     }
38     printf(Auto"\n", res);
39 }
40 
41 int main() {
42     init();
43     solve();
44     return 0;
45 }
Problem B

Codeforces 940C Phone Numbers

题目大意

  给定一个由小写字母组成且长度为$n$的字符串$s$,要求输出一个字符串$t$,满足:

  1. $t$中出现的字符在$s$中也出现过
  2. 它的长度为$k$
  3. $t$的字典序大于$s$
  4. 在满足上述条件的所有串中,是字典序最小的一个

  题目保证存在解。

  当$k > n$时,直接输出字符串$s$,再补上$s$中最小的字符。

  否则找到$s$中从第$k$个字符往前找第一个不是最大的字符,把它变为略比它的字符。

  然后后面的补最小的字符。

Code

技术分享图片
 1 /**
 2  * Codeforces
 3  * Problem#940C
 4  * Accepted
 5  * Time: 31ms
 6  * Memory: 2100k 
 7  */ 
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11 
12 int n, k;
13 int mi = 0, ma = 25;
14 boolean exist[26];
15 char str[100005];
16 
17 inline void init() {
18     scanf("%d%d", &n, &k);
19     memset(exist, false, sizeof(exist));
20     scanf("%s", str + 1);
21 } 
22 
23 inline void solve() {
24     for (int i = 1; i <= n; i++)
25         exist[str[i] - a] = true;
26     for (mi = 0; !exist[mi]; mi++);
27     for (ma = 25; !exist[ma]; ma--);
28     if (n < k) {
29         printf("%s", str + 1);
30         for (int i = n + 1; i <= k; i++)
31             putchar(mi + a);
32         return;
33     }
34     int p;
35     for (p = k; p && str[p] == ma + a; p--);
36     str[p]++;
37     while (!exist[str[p] - a])
38         str[p]++;
39     for (p = p + 1; p <= k; p++)
40         str[p] = mi + a;
41     str[k + 1] = 0;
42     puts(str + 1);
43 }
44 
45 int main() {
46     init();
47     solve();
48     return 0;
49 }
Problem C

Codeforces 940D Alena And The Heater

题目大意

  给定一个数组$a$,和一个01串$b$,$b$按照如下方式生成(请自行阅读英文)

  技术分享图片

  请你找出一组合法的$l, r$,保证输入存在解。

  发现生成方式比较特殊。

  于是根据生成方式更新$l, r$即可。

Code

技术分享图片
 1 /**
 2  * Codeforces
 3  * Problem#940D
 4  * Accepted
 5  * Time: 31ms
 6  * Memory: 2500k
 7  */ 
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 
11 int n;
12 int a[100005];
13 char b[100005];
14 
15 inline void init() {
16     scanf("%d", &n);
17     for (int i = 1; i <= n; i++)
18         scanf("%d", a + i);
19     scanf("%s", b + 1);
20 }
21 
22 char sameNumber(int p) {
23     char x = b[p - 1];
24     for (int i = 2; i <= 4; i++)
25         if (b[p - i] != x)
26             return 2;
27     return x;
28 }
29 
30 int l = -1e9, r = 1e9;
31 
32 inline void solve() {
33     for (int i = 5; i <= n; i++) {
34         char c = sameNumber(i);
35         if (c == 2)    continue;
36         if (c == b[i])    continue;
37         if (c == 1) {
38             for (int j = 0; j <= 4; j++)
39                 r = min(r, a[i - j] - 1);
40         } else {
41             for (int j = 0; j <= 4; j++)
42                 l = max(l, a[i - j] + 1);
43         }
44     }
45     printf("%d %d", l, r);
46 }
47 
48 int main() {
49     init();
50     solve();
51     return 0;
52 }
Problem D

Codeforces 940E Cashback

题目大意

  给定一个长度为$n$的数组和常数$c$,要求你对它进行划分。划分长度为$k$一段的代价是其中所有除去前$\left \lfloor \frac{k}{c} \right \rfloor$小的数的和。定义一个划分的代价是划分的所有段的代价的和。

  问最小的代价和。

  一段代价可以表示为这一段的和减去前$\left \lfloor \frac{k}{c} \right \rfloor$小的数的和。

  那么考虑两段连续的长度为$c$的合并到一起,这样会使得前2小的和变小。所以划分的最长的长度不会超过$2c - 1$

  那么考虑长度在$c + 1$和$2c - 1$之间的段。我只需要留一个长度为$c$的段,把它和剩下的分开。这样看的话,划分的一段的长度不会超过$c$。

  继续考虑长度小于$c$的段,它的代价直接就是它中间的元素的和。因此可以直接把它分成一些只有1个元素的段。

  因此存在一种最优方案满足划分的每一段长度不是1就是$c$。

  因此我只用维护连续$c$个元素的最小值,以及它们的和。

  于是上单调队列。

  时间复杂度$O(n)$。

Code

技术分享图片
 1 /**
 2  * Codeforces
 3  * Problem#940E
 4  * Accepted
 5  * Time: 31ms
 6  * Memory: 3700k
 7  */ 
 8 #include <bits/stdc++.h>
 9 #ifndef WIN32
10 #define Auto "%lld"
11 #else
12 #define Auto "%I64d"
13 #endif
14 using namespace std;
15 
16 #define ll long long
17 
18 const int N = 100005;
19 
20 int n, c;
21 int st = 1, ed = 0;
22 ll f[N];
23 int ar[N];
24 int que[N];
25 
26 inline void init() {
27     scanf("%d%d", &n, &c);
28     for (int i = 1; i <= n; i++)
29         scanf("%d", ar + i);
30 }
31 
32 inline void solve() {
33     
34     f[1] = 0;
35     ll sum = 0;
36     for (int i = 1; i <= n; i++) {
37         while (ed >= st && ar[que[ed]] >= ar[i])    ed--;
38         que[++ed] = i;
39         f[i] = f[i - 1] + ar[i];
40         sum += ar[i];
41         while (ed >= st && que[st] <= i - c)    st++;
42         if (i >= c)
43             sum -= ar[i - c], f[i] = min(f[i], f[i - c] + sum - ar[que[st]]);    
44     }
45     
46     printf(Auto"\n", f[n]);    
47 }
48 
49 int main() {
50     init();
51     solve();
52     return 0;
53 } 
Problem E

 

Codeforces Round #466 (Div. 2) Problem A - E

标签:特殊   number   amp   ima   ide   add   单调队列   tag   enum   

原文地址:https://www.cnblogs.com/yyf0309/p/Codeforces_Round_466_Div_2.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!