• CodeForces ZeptoLab Code Rush 2015


    拖了好久的题解,想想还是补一下吧。

    A. King of Thieves

    直接枚举起点和5个点之间的间距,进行判断即可。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 char s[110];
     5 
     6 int main()
     7 {
     8     //freopen("in.txt", "r", stdin);
     9 
    10     int n;
    11     bool ans = false;
    12     scanf("%d%s", &n, s);
    13     for(int q = 0; q < n && !ans; q++) if(s[q] == '*')
    14         for(int l = 1; q + 4*l < n; l++)
    15         {
    16             int i;
    17             for(i = 1; i <= 4; i++) if(s[q + i*l] == '.') break;
    18             if(i > 4) { ans = true; break; }
    19         }
    20 
    21     printf("%s
    ", ans ? "yes" : "no");
    22 
    23     return 0;
    24 }
    代码君

    B. Om Nom and Dark Park (DFS)

    给一个完全二叉树,增加若干条边的权值,使得从根到每个叶节点的权值之和相同。

    直接从下往上维护这颗树,累加所增加的权值。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 const int maxn = (1 << 12) + 10;
     5 LL a[maxn], num[maxn], ans, sum[maxn];
     6 
     7 int n;
     8 
     9 void dfs(int o, int d)
    10 {
    11     if(d > n) return;
    12     int lc = o*2, rc = o*2+1;
    13     dfs(lc, d+1); dfs(rc, d+1);
    14     int m = max(sum[lc] + a[lc], sum[rc] + a[rc]);
    15     ans += m - (sum[lc] + a[lc]);
    16     ans += m - (sum[rc] + a[rc]);
    17     sum[o] = m;
    18 }
    19 
    20 int main()
    21 {
    22     //freopen("in.txt", "r", stdin);
    23 
    24     scanf("%d", &n);
    25     for(int i = 2; i < (1<<(n+1)); i++) scanf("%I64d", &a[i]);
    26     dfs(1, 1);
    27     printf("%I64d
    ", ans);
    28 
    29     return 0;
    30 }
    代码君

    C. Om Nom and Candies (部分贪心)

    关于部分贪心可以看高逸涵的09年国家队论文。

    这道题可以分成两种情况,用不同的办法来解决。

    • 有一种糖果的质量大于等于1000,那么我们枚举这种糖果的数量来求最大值。根据题目数据范围,循环的次数不会超过109 / 103 = 106.
    • 两种糖果的质量都小于1000,然后选一个性价比比较高的糖果。不妨设,那么我们说蓝色糖果的数量一定小于Wr。这样贪心的理由就是,如果有Wr个蓝色糖果,我们完全可以换成Wb个红色糖果。因为这种方案的糖果质量是一样的,但是总价值是HbWr < HrWb。所以我们可以枚举蓝色糖果的数量,来求最优解,并且循环的次数不超过1000.
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long LL;
     4 
     5 
     6 int main()
     7 {
     8     LL c, hr, hb, wr, wb, ans = 0;
     9     scanf("%I64d%I64d%I64d%I64d%I64d", &c, &hr, &hb, &wr, &wb);
    10     const int M = 1000;
    11     if(wb > wr) { swap(hr, hb); swap(wr, wb); }
    12     if(wr > M)
    13     {
    14         for(LL i = 0; i * wr <= c; i++)
    15         {
    16             LL j = (c - i * wr) / wb;
    17             ans = max(ans, (LL)i*hr + j*hb);
    18         }
    19         cout << ans << endl;
    20         return 0;
    21     }
    22 
    23     if(hb*wr > hr*wb) { swap(hr, hb); swap(wr, wb); }
    24     for(LL i = 0; i <= wr && i * wb <= c; i++)
    25     {
    26         LL j = (c - i * wb) / wr;
    27         ans = max(ans, i*hb+j*hr);
    28     }
    29     cout << ans << endl;
    30 
    31     return 0;
    32 }
    代码君

    D. Om Nom and Necklace (KMP)

    题解转自:http://cyberzhg.github.io/blog/Online-Judge/CF526ABCDE/

    这道题最终还是并没有看明白 r mod k是怎么来的,(⊙﹏⊙)b

     1 #include <cstdio>
     2 
     3 const int maxn = 1000000 + 10;
     4 char s[maxn];
     5 int f[maxn], m, k;
     6 
     7 void getFail()
     8 {
     9     f[0] = 0, f[1] = 0;
    10     for(int i = 1; i < m; i++)
    11     {
    12         int j = f[i];
    13         while(j && s[i] != s[j]) j = f[j];
    14         f[i+1] = s[i] == s[j] ? j+1 : 0;
    15     }
    16 }
    17 
    18 int main()
    19 {
    20     //freopen("in.txt", "r", stdin);
    21     scanf("%d%d%s", &m, &k, s);
    22     getFail();
    23 
    24     for(int i = 1; i <= m; i++)
    25     {
    26         int l = i - f[i];
    27         int R = i / l;
    28         if(i % l == 0)
    29             printf("%c", R / k >= R % k ? '1' : '0');
    30         else
    31             printf("%c", R / k > R % k ? '1' : '0');
    32     }
    33     printf("
    ");
    34 
    35     return 0;
    36 }
    代码君

    E. Transmitting Levels

    在CF上发现了一种非常神的解法。首先预处理一下前缀和,然后用一个链表head[i]记录以第i个节点为结尾的,每段上的数之和不超过b的第一个数的下标。当这个跨度大于等于n的时候就说明找到答案了。

    len就是记录分成了多少段。

    我说的可能不太清楚,但是代码十分好懂,而且十分简练。感觉比官方题解要好很多。

    但是我不太能证明它的正确性,为什么一旦找到i - head[i] >= n就输出答案了呢,也就是为什么后面不可能有最优解了呢?

     1 #include <cstdio>
     2 
     3 typedef long long LL;
     4 const int maxn = 2000000 + 10;
     5 LL a[maxn], sum[maxn], len[maxn], head[maxn];
     6 
     7 int main()
     8 {
     9     //freopen("in.txt", "r", stdin);
    10 
    11     int n, q;
    12     scanf("%d%d", &n, &q);
    13     for(int i = 1; i <= n; i++) { scanf("%I64d", &a[i]); a[i+n] = a[i]; }
    14     for(int i = 1; i <= n * 2; i++) { sum[i] = sum[i-1] + a[i]; head[i] = i; }
    15     while(q--)
    16     {
    17         int b; scanf("%d", &b);
    18         for(int i = n + 1, j = 1; i <= n * 2; i++)
    19         {
    20             while(sum[i] - sum[j] > b) j++;
    21             head[i] = head[j];
    22             len[i] = len[j] + 1;
    23             if(i - head[i] >= n) { printf("%I64d
    ", len[i]); break; }
    24         }
    25     }
    26 
    27     return 0;
    28 }
    代码君
  • 相关阅读:
    排序
    最小栈
    移除链表元素
    回文链表
    maven自动建立目录骨架
    maven的结构和构建命令
    递归
    链表的中间结点
    括号匹配
    软件工程个人作业01
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4428276.html
Copyright © 2020-2023  润新知