zoukankan      html  css  js  c++  java
  • 比赛-Round 1 (13 Jul, 2018)

    1. 分队

    每名选手都要属于一个队伍,考虑 A[i] 最大的选手是必须选的。考虑与他同一队的选手,显然尽量选 A[i] 大的其他选手,并且选的人数越少越好,因为选手越多,可划分的队伍数就越多。这样就得到了一个显然的贪心。这样做是错误的,据说可以过 80 分。1 2 4 5 5 5 5 5 这组数据在这样的贪心策略下无解,而实际上存在一个答案为 2 的解 (1, 2, 4) (5, 5, 5, 5, 5) 。所以其实并不是每个队选的人越少越好,因为有的选手的需求在其它队伍组合里无法满足,必须把他加入人数更多的队伍。因此考虑 DP ,在贪心的基础上(从小到大排序),f[i] 表示前 i 个选手最多可分队伍数。 f[i] = f[j] + 1 (0 <= j <= i-A[i]) ,前缀和优化一下就是 O(n) 的了。

     1 #include <stdio.h>
     2 #include <algorithm>
     3 
     4 using namespace std;
     5 
     6 int A[1200000], f[1200000], M[1200000];
     7 
     8 int main()
     9 {
    10     int N, i;
    11     scanf("%d", &N);
    12     for (i = 1; i <= N; ++i)
    13         scanf("%d", &A[i]);
    14     sort(A+1, A+1+N);
    15     M[0] = 0;
    16     for (i = 1; i <= N; ++i) {
    17         if (i-A[i] >= 0) f[i] = M[i-A[i]]+1;
    18         else f[i] = 0;
    19         M[i] = max(M[i-1], f[i]);
    20     }
    21     printf("%d
    ", f[N]);
    22     return 0;
    23 }

    2. 子矩阵
    枚举矩阵的 up, down, 考虑每一列可以往左和往右扩展多远。用单调栈维护。O(n3)。

     1 #include <stdio.h>
     2 #include <algorithm>
     3 #include <string.h>
     4 #include <stack>
     5 
     6 using namespace std;
     7 
     8 
     9 stack<int> S;
    10 int A[320][320], Mn[320], R[320], ans[320*320];
    11 
    12 
    13 int main()
    14 {
    15     int i, j, up, dn, N, M;
    16     scanf("%d%d", &N, &M);
    17     for (i = 1; i <= N; ++i)
    18         for (j = 1; j <= M; ++j)
    19             scanf("%d", &A[i][j]);
    20     for (up = 1; up <= N; ++up)
    21         for (dn = up; dn <= N; ++dn) {
    22             for (i = 1; i <= M; ++i)
    23                 if (up == dn) Mn[i] = A[dn][i];
    24                 else Mn[i] = min(Mn[i], A[dn][i]);
    25             memset(R, 0, sizeof R);
    26             
    27             for (i = 1; i <= M; ++i) {
    28                 while (!S.empty() && Mn[S.top()] > Mn[i])
    29                     R[S.top()] = i-S.top(), S.pop();
    30                 S.push(i);
    31             }
    32             while (!S.empty()) R[S.top()] = M-S.top()+1, S.pop();
    33             
    34             for (i = M; i >= 1; --i) {
    35                 while (!S.empty() && Mn[S.top()] > Mn[i])
    36                     ans[Mn[S.top()]] += R[S.top()]*(S.top()-i), S.pop();
    37                 S.push(i);
    38             }
    39             while (!S.empty()) ans[Mn[S.top()]] += R[S.top()]*S.top(), S.pop();
    40         }
    41     for (i = 1; i <= N*M; ++i) printf("%d
    ", ans[i]);
    42     return 0;
    43 }

    3. 数字对

    对于 (mx, mn) (满足 mx > mn) ,它显然是且只能是由 (mx-mn, mn) 操作得到的。所以反向考虑问题枚举所有的 (n, i) ,计算它得到 (1, 1) 的步数,取最小值。这个过程类似欧几里得辗转相除,处理之后可以把单次计算步数优化到 O(logN) ,所以整体是 O(NlogN) 的。

    不过玄学迭代加深搜索真的非常强。

    搜索代码:

     1 #include <cstdio>
     2 
     3 int depth, N;
     4 int Fi[53];
     5 bool flag;
     6 
     7 void diu(int mx, int mn, int d)
     8 {
     9     if (d == depth) {
    10         if (mx == N || mn == N)
    11             flag = true;
    12         return;
    13     }
    14     if (mx+(depth-d)*mn > N || Fi[depth-d+1]*mx+Fi[depth-d]*mn < N) return;
    15     diu(mx+mn, mn, d+1);
    16     if (flag) return;
    17     diu(mx+mn, mx, d+1);
    18     if (flag) return;
    19 }
    20 
    21 int main()
    22 {
    23     scanf("%d", &N);
    24     Fi[1] = Fi[2] = 1;
    25     for (depth = 0; depth <= 50; ++depth) {
    26         if (depth > 1) Fi[depth+1] = Fi[depth]+Fi[depth-1];
    27         flag = false;
    28         diu(1, 1, 0);
    29         if (flag) break;
    30     }
    31     printf("%d
    ", depth);
    32     return 0;
    33 }

    我改悔罢!
    1 题想到了贪心,手构样例没卡住自己,以为是正确的,因为不知道的原因超时拿了 60 分. 所以说贪心虽然机智,必须反复验证其正确性啊OrzOrz
    2 题考虑过二维树状数组,然后考虑到对于第 i 答案,是比第 i-1 个多了一个限制条件的:不能选矩阵中第 i-1 个值。然后考虑这个值在矩阵的位置在当前第 i 个值在矩阵的位置的 左上,右下,…… 似乎就很像一个容斥原理,然而之后就推不动了。卡了整整一个半小时。而且由于 P3 做得比较快,时间还算充裕,先没有打暴力,一直纠结正解。最后时间紧打了发连样例都不能过的假容斥交了,爆 0。所以说不管能不能搞出正解,先写暴力呀,留着对拍也好。

    3 题第一反应是搜索,迭代加深由于限制非常强,对拍了一下发现在题目范围内可以很快通过,所以没花太多时间就放下这道题了。考试结束之后实测了在 1e8 标程被卡死的情况下,迭代加深搜索仍然很快出答案,非常玄学,可能是因为这种迭代加深搜索的复杂度与 Fibonacci 数列有关吧。

  • 相关阅读:
    poj 3636
    poj 1065 Wooden Sticks
    2017北京国庆刷题Day6 afternoon
    2017北京国庆刷题Day5 afternoon
    2017北京国庆刷题Day3 afternoon
    2017北京国庆刷题Day3 morning
    2017北京国庆刷题Day2 afternoon
    2017北京国庆刷题Day2 morning
    poj2420 A Star not a Tree?
    NOIP2016 愤怒的小鸟
  • 原文地址:https://www.cnblogs.com/ghcred/p/9305411.html
Copyright © 2011-2022 走看看