zoukankan      html  css  js  c++  java
  • Codeforces题解集

    Codeforces 2019年12月19日到 2020年2月12日 的部分比赛题

    Educational Codeforces Round 82 (Rated for Div. 2)

    Fill The Bag

      给出m(≤1e5)个盒子,盒子的大小是2的幂次。可以选择把一个盒子分成大小相同的两部分,问最少执行几次分盒子的操作,可以装满大小为n(≤1e18)的背包。

      把n转化为二进制,代表可以由若干种2的幂次的盒子各一个装满。从小往大贪心地使用已有的盒子,不足时把第一个比它大的盒子分开。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 
     6 const int maxn = 1e6 + 5;
     7 
     8 ll t, n, m, a[maxn];
     9 ll num[70];
    10 
    11 int main() {
    12     ios::sync_with_stdio(false);
    13     cin.tie(nullptr);
    14     cin >> t;
    15     while (t--) {
    16         cin >> n >> m;
    17         ll tot = 0;
    18         memset(num, 0, sizeof(num));
    19         inc(i, 0, m - 1) {
    20             cin >> a[i];
    21             tot += a[i];
    22             num[(int)log2((double)a[i])]++;
    23         }
    24         if (tot < n) {
    25             cout << "-1
    ";
    26             continue;
    27         }
    28         ll ans = 0;
    29         for (int i = 0; n; i++) {
    30             if (n & 1) {
    31                 if (num[i])
    32                     num[i]--;
    33                 else
    34                     inc(j, i + 1, 31) if (num[j]) {
    35                         num[j]--;
    36                         num[i] += (1 << (j - i)) - 1;
    37                         ans += j - i;
    38                         break;
    39                     }
    40             }
    41             num[i + 1] += num[i] / 2;
    42             n >>= 1;
    43         }
    44         cout << ans << "
    ";
    45     }
    46 }
    View Code

    Erase Subsequences

      给出两个串s, t,长度≤400,问s的两个不相交的子序列能否拼接成 t.

      枚举 t 的分界处,设左子串为t1,右子串为t2,遍历s,其实就是考虑是放到t1还是t2。dp[i]表示已匹配到t1[i]时,t2最远匹配到t2[dp[i]],当dp[cnt]=size(t)时表示匹配成功。时间复杂度O(n^3)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 
     6 const int maxn = 1e3 + 5;
     7 
     8 int c;
     9 char s[maxn], t[maxn];
    10 
    11 int main() {
    12   //  ios::sync_with_stdio(false);
    13   //  cin.tie(nullptr);
    14     cin >> c;
    15     while (c--) {
    16         scanf("%s%s", s, t + 1);
    17         int l1 = strlen(s), l2 = strlen(t + 1), f = 0;
    18         inc(cnt, 1, l2) {
    19             vector<int> dp(cnt + 1, -1), nxt(cnt + 1);
    20             dp[0] = cnt;
    21             inc(i, 0, l1 - 1) {
    22                 inc(j, 0, cnt) nxt[j] = dp[j];
    23                 inc(j, 0, cnt - 1) if (s[i] == t[j + 1] && dp[j] != -1)
    24                     nxt[j + 1] = max(nxt[j + 1], dp[j]);
    25                 inc(j, 0,
    26                     cnt) if (dp[j] != -1 && dp[j] < l2 && s[i] == t[dp[j] + 1])
    27                     nxt[j] = max(nxt[j], dp[j] + 1);
    28                 inc(j, 0, cnt) dp[j] = nxt[j];
    29             }
    30             if (dp[cnt] == l2) {
    31                 f = 1;
    32                 break;
    33             }
    34         }
    35         if (f)
    36             printf("YES
    ");
    37         else
    38             printf("NO
    ");
    39     }
    40 }
    View Code

    Codeforces Round #618 (Div. 1)

    Anu Has a Function

      定义f(x, y) = x | y - y,给出一个数列,要改变顺序顺序后,使得f(f(x1, x2), x3), …)最大

      这种题目直接考虑01的四种组合结果会是什么。发现只有f(1, 0)结果会是1,所以对于某一数位,只有1 0 0 …是有意义的。找到最高的数位满足这种状况,在确定了第一个数后,后面的数无论是什么顺序都不影响了。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 #define dec(i, l, r) for (int i = l; i >= r; i--)
     6 
     7 const int maxn = 1e6 + 5;
     8 
     9 int a[maxn], n, vis[maxn];
    10 
    11 int main() {
    12     ios::sync_with_stdio(false);
    13     cin.tie(nullptr);
    14     cin >> n;
    15     inc(i, 0, n - 1) cin >> a[i];
    16     int res = -1;
    17     dec(i, 30, 0) {
    18         int pos = -1;
    19         inc(j, 0, n - 1) if (a[j] >> i & 1) {
    20             if (pos == -1)
    21                 pos = j;
    22             else
    23                 pos = -2;
    24         }
    25         if (pos >= 0) {
    26             res = pos;
    27             break;
    28         }
    29     }
    30     if (res >= 0) {
    31         cout << a[res] << " ";
    32         vis[res] = 1;
    33     }
    34     inc(i, 0, n - 1) if (!vis[i]) cout << a[i] << " ";
    35 }
    View Code

     

    Aerodynamic

      给出一个凸多边形P,我们可以看作一个空心的框,想像(0, 0) 处有一个钉子,框在保证钉子在里面的前提下平移,经过的区域形成一个新的多边形T。问P与T是否相似。

      另一种定义,P中存在向量(x, y),则点(x, y)在T内(上)。

      考虑到存在向量(x,y)就必存在(-x,-y),T必然是中心对称。那么当P是中心对称时,使P中心点在原点,可以发现若(x, y)在P上,则(2x, 2y)在T上;而对于P外的某点,考虑中心对称的且在边上的两点,构成向量(x, y),必不存在该方向上更长的向量(P是凸包)。所以P与T相似,且相似比为1:2。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 
     6 const int maxn = 1e6 + 5;
     7 
     8 ll x[maxn], y[maxn];
     9 int n;
    10 
    11 int main() {
    12     ios::sync_with_stdio(false);
    13     cin.tie(nullptr);
    14     cin >> n;
    15     inc(i, 0, n - 1) cin >> x[i] >> y[i];
    16     if (n & 1) {
    17         printf("no
    ");
    18         exit(0);
    19     }
    20     ll cx = x[0] + x[n / 2], cy = y[0] + y[n / 2];
    21     inc(i, 1,
    22         n / 2 - 1) if (x[i] + x[i + n / 2] != cx || y[i] + y[i + n / 2] != cy) {
    23         printf("no
    ");
    24         exit(0);
    25     }
    26     printf("yes
    ");
    27 }
    View Code

     

    Water Balance

      给出一个数列,可以使一个连续区间的数,都变成该区间的平均数。问经过任意次操作,字典序最小的结果

      考虑我们总是优先使第一个最小化,第一个最小化后,继续检查后面能否更小。维护一个递增的单调栈,出现逆序就合并。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 #define dec(i, l, r) for (int i = l; i >= r; i--)
     6 
     7 const int maxn = 1e6 + 5;
     8 
     9 ll a[maxn];
    10 int n;
    11 
    12 struct p {
    13     double ave;
    14     int num;
    15 };
    16 stack<p> s;
    17 vector<double> res;
    18 
    19 int main() {
    20     ios::sync_with_stdio(false);
    21     cin.tie(nullptr);
    22     cin >> n;
    23     inc(i, 1, n) cin >> a[i];
    24     inc(i, 1, n) {
    25         double sum = a[i];
    26         int num = 1;
    27         while (!s.empty() && sum / num < s.top().ave) {
    28             sum += s.top().ave * s.top().num;
    29             num += s.top().num;
    30             s.pop();
    31         }
    32         s.push({sum / num, num});
    33     }
    34     while (!s.empty()) {
    35         inc(i, 1, s.top().num) res.push_back(s.top().ave);
    36         s.pop();
    37     }
    38     dec(i, n - 1, 0) printf("%.12f ", res[i]);
    39 }
    View Code

     

     

     Educational Codeforces Round 81 (Rated for Div. 2)

    Same GCDs

      给出a和m,1≤a<m≤1e10,问有多少个x,0≤x<m,gcd(a, m)==gcd(a+x, m)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 
     6 int t;
     7 ll a, m;
     8 
     9 const int maxnum = 1e5;
    10 int prim[maxnum], pvis[maxnum + 5], pcnt;
    11 void getprim() {
    12     for (int i = 2; i <= maxnum; i++) {
    13         if (!pvis[i]) prim[++pcnt] = i;
    14         for (int j = 1; j <= pcnt && prim[j] * i <= maxnum; j++) {
    15             pvis[prim[j] * i] = 1;
    16             if (i % prim[j] == 0) break;
    17         }
    18     }
    19 }
    20 
    21 ll cal(ll x) {
    22     ll org = x;
    23     for (int i = 1; i <= pcnt && x > 1; i++) {
    24         if (x % prim[i] == 0) org = org / prim[i] * (prim[i] - 1);
    25         while (x % prim[i] == 0) x /= prim[i];
    26     }
    27     if (x > 1) org = org / x * (x - 1);
    28     return org;
    29 }
    30 
    31 int main() {
    32     getprim();
    33     cin >> t;
    34     while (t--) {
    35         cin >> a >> m;
    36         cout << cal(m / __gcd(a, m)) << "
    ";
    37     }
    38 }
    View Code

     

    Permutation Separation

      给出一个n的排列,2≤n≤2e5,每个数有权值ai,现要分成两个非空子串,并对应两个数字集合,通过付出每个数字的权值的代价,可以把一个数字从原来的集合移动到另一个集合里。要使左子串对应的数字集合里的所有数都小于右字串对应的集合,或使若某一集合为空集,问最小代价

      易知最终左子串对应的集合必然是1,2,,,n的一个前缀,扫描一遍,维护一个“变成前缀为i的集合需要的代价”的线段树

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 
     6 const int maxn = 2e5 + 5;
     7 
     8 int n, p[maxn], a[maxn];
     9 int val[maxn];
    10 ll fv;
    11 
    12 ll res, tmp;
    13 
    14 ll w[4 * maxn], f[4 * maxn];
    15 
    16 void build(int k, int l, int r) {
    17     if (l == r) {
    18         fv += val[l];
    19         w[k] = fv;
    20         return;
    21     }
    22     int m = (l + r) / 2;
    23     build(2 * k, l, m);
    24     build(2 * k + 1, m + 1, r);
    25     w[k] = min(w[2 * k], w[2 * k + 1]);
    26 }
    27 
    28 void down(int k, int l, int r) {
    29     f[2 * k] += f[k];
    30     f[2 * k + 1] += f[k];
    31     w[2 * k] += f[k];
    32     w[2 * k + 1] += f[k];
    33     f[k] = 0;
    34 }
    35 
    36 void change(int k, int l, int r, int a, int b, int val) {
    37     if (a <= l && r <= b) {
    38         w[k] += val;
    39         f[k] += val;
    40         return;
    41     }
    42     if (f[k]) down(k, l, r);
    43     int m = (l + r) / 2;
    44     if (a <= m) change(2 * k, l, m, a, b, val);
    45     if (b > m) change(2 * k + 1, m + 1, r, a, b, val);
    46     w[k] = min(w[2 * k], w[2 * k + 1]);
    47 }
    48 
    49 int main() {
    50     cin >> n;
    51     inc(i, 1, n) cin >> p[i];
    52     inc(i, 1, n) {
    53         cin >> a[i];
    54         val[p[i]] = a[i];
    55     }
    56     build(1, 0, n);
    57     res = a[1];
    58     for (int i = 1; i < n; i++) {
    59         change(1, 0, n, 0, p[i] - 1, a[i]);
    60         change(1, 0, n, p[i], n, -a[i]);
    61         res = min(res, w[1]);
    62     }
    63     cout << res;
    64 }
    View Code

     

     

    Educational Codeforces Round 80 (Rated for Div. 2)

    Minimax Problem

      给出N×M的矩阵,N≤3e5,M≤8。现取出其中两行,“合并”成新的一行。所谓合并,是在相同位置的数取最大值。现在要最大化该数列的最小值,输出选取的两行行号

      比较容易想到是二分答案。judge时要让每一个位置至少有一个数大于ans,可以把大于ans的数位hash成1,然后在至多2**M的hash数组里寻找是否有满足条件的两列。这里降低时间复杂度是利用了2**M<N的特点。注意二分的时候,避免没有judge为true(即ans实际为0,却不会运行到一步)的情况

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 #define pii pair<int, int>
     6 #define fi first
     7 #define se second
     8 #define pb push_back
     9 
    10 const int maxn = 3e5 + 5;
    11 
    12 int a[maxn][10], n, m, r1, r2;
    13 int h[300];
    14 
    15 inline bool judge(int ans) {
    16     memset(h, 0, sizeof(h));
    17     inc(i, 0, n - 1) {
    18         int val = 0;
    19         inc(j, 0, m - 1) {
    20             if (a[i][j] >= ans) val += 1 << j;
    21         }
    22         h[val] = i + 1;
    23     }
    24     int sz = (1 << m) - 1;
    25     inc(i, 0, sz) {
    26         inc(j, 0, sz) if ((i | j) == sz && h[i] && h[j]) {
    27             r1 = h[i], r2 = h[j];
    28             return true;
    29         }
    30     }
    31     return false;
    32 }
    33 
    34 int main() {
    35     scanf("%d %d", &n, &m);
    36     inc(i, 0, n - 1) inc(j, 0, m - 1) scanf("%d", &a[i][j]);
    37     int l = 0, r = (int)1e9 + 1, ans = -1;
    38     while (l + 1 < r) {
    39         int m = (r - l) / 2 + l;
    40         if (judge(m))
    41             l = m, ans = m;
    42         else
    43             r = m;
    44     }
    45     if (ans == -1)
    46         printf("1 1
    ");
    47     else
    48         cout << r1 << " " << r2;
    49 }
    View Code

     

    Messenger Simulator 

      初始为1,2,,,n的一个排列,代表n位好友的消息列表。给出m条消息,其中每一条都会使对应的好友消息在列表中置顶,即排列中的该数字被提前到第一个位置。问每个人在消息列表中最靠前和最靠后的位置。

      考虑到一个人的位置只有在发消息时会减少,否则只会递增。所以,只关心在发消息时以及结束时刻他前面有多少人。建立一个n+m的BIT,初始时后n个位置置为1,代表了这n个人;每次处理一位好友消息时,查询前缀和,更新最大值,把他置于所有人前一位,并删去原来所在位置.

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 #define lowbit(x) x&(-x)
     6 
     7 const int maxn = 6e5 + 5;
     8 
     9 int n, m, q;
    10 
    11 int f[maxn];
    12 void add(int x, int val) {
    13     for (; x <= n + m; x += lowbit(x)) f[x] += val;
    14 }
    15 int get(int x) {
    16     int res = 0;
    17     for (; x; x -= lowbit(x)) res += f[x];
    18     return res;
    19 }
    20 
    21 int a[maxn], b[maxn], pos[maxn];
    22 
    23 int main() {
    24     cin >> n >> m;
    25     inc(i, 1, n) {
    26         a[i] = b[i] = i;
    27         pos[i] = m + i;
    28         add(i + m, 1);
    29     }
    30     inc(i, 1, m) {
    31         cin >> q;
    32         a[q] = 1;
    33         b[q] = max(b[q], get(pos[q] - 1) + 1);
    34         add(pos[q], -1);
    35         pos[q] = m - i + 1;
    36         add(m - i + 1, 1);
    37     }
    38     inc(i, 1, n) b[i] = max(b[i], get(pos[i] - 1) + 1);
    39     inc(i, 1, n) printf("%d %d
    ", a[i], b[i]);
    40 }
    View Code

      

     

    Codeforces Round #610 (Div. 2)

    Petya and Exam

      有一次测验,有N道题,考试时间T,已知每一题是容易题还是困难题,解决前者需要时间a,后者需要b,每道题有个ti,考生在离开考场(可以选择提前离场)时若不小于该时间而未解决该题,他总分就是0分。问考生最多能获得多少分(解决一题得一分)。

      思维点在于考虑到每个ti的前一秒是离场的最佳时间,检查能否把必须做的题了,外加做额外的题,更新答案。另外考试结束时也要检查是否可以更新答案。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 
     6 const int maxn = 2e5 + 5;
     7 
     8 int m, n, t, a, b;
     9 
    10 struct problem {
    11     int hard, gg;
    12     bool operator<(const problem& o) const { return gg < o.gg; }
    13 } p[maxn];
    14 
    15 int main() {
    16     ios::sync_with_stdio(false);
    17     cin.tie(nullptr);
    18     cin >> m;
    19     while (m--) {
    20         cin >> n >> t >> a >> b;
    21         ll ea = 0, eb = 0;
    22         inc(i, 0, n - 1) {
    23             cin >> p[i].hard;
    24             ea += p[i].hard == 0;
    25             eb += p[i].hard == 1;
    26         }
    27         inc(i, 0, n - 1) cin >> p[i].gg;
    28         sort(p, p + n);
    29         p[n] = {-1, t + 1};
    30         ll task = 0;
    31         ll na = 0, nb = 0, res = 0;
    32         for (int i = 0, j; i <= n; i = j) {
    33             if (p[i].gg - 1 >= task) {
    34                 ll tot = na + nb, tmp = p[i].gg - 1 - task;
    35                 if (tmp <= (ea - na) * a)
    36                     tot += tmp / a;
    37                 else {
    38                     tot += ea - na;
    39                     tmp -= (ea - na) * a;
    40                     if (tmp <= (eb - nb) * b)
    41                         tot += tmp / b;
    42                     else
    43                         tot += eb - nb;
    44                 }
    45                 res = max(res, tot);
    46             }
    47             j = i;
    48             while (j <= n && p[j].gg == p[i].gg) {
    49                 if (p[j].hard == 0)
    50                     task += a, na++;
    51                 else
    52                     task += b, nb++;
    53                 j++;
    54             }
    55         }
    56         cout << res << "
    ";
    57     }
    58 }
    View Code

     

    Enchanted Artifact

      交互题。定义Edit distance是串s经过增,删,改(每次一个字符)变成串t的次数。现有一个串s(size≤300),用户询问串t(size≤300),返回Edit distance,最多询问s.size+2次(包括最终返回0的“询问”)

      先询问300个a的串和300个b的串得到s有几个a和几个b,依据:由s变成全a只能把b改成a以及添加a。此时,我们也知道了如果询问一个与s长度相同全为b的串(记作tt)会得到的答案。然后询问这样的串t,长度与s相同,除了某一位置为a,其他都是b,可以推理出,a的位置与s匹配与 询问tt的返回值-1 是等价的。又注意到最后一个位置可以通过计算a的个数得出,所以无须询问,总询问次数刚好size+2次。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define inc(i, l, r) for (int i = l; i <= r; i++)
     4 
     5 int a, b, x, n;
     6 
     7 void read() {
     8     cout << '
    ';
     9     fflush(stdout);
    10     cin >> x;
    11     if (x == 0) exit(0);
    12 }
    13 
    14 int main() {
    15     inc(i, 1, 300) cout << 'a';
    16     read();
    17     a = 300 - x;
    18 
    19     inc(i, 1, 300) cout << 'b';
    20     read();
    21     b = 300 - x;
    22 
    23     n = a + b;
    24     string res(n, 'b');
    25 
    26     int ta = 0;
    27     inc(i, 0, n - 2) {
    28         inc(j, 0, n - 1) if (i == j) cout << "a";
    29         else cout << "b";
    30         read();
    31         if (x == a - 1) {
    32             res[i] = 'a';
    33             ta++;
    34         }
    35     }
    36     if (ta != a) res[n - 1] = 'a';
    37     cout << res;
    38     read();
    39 }
    View Code

     

     

    Codeforces Round #607 (Div. 1)

    Beingawesomeism

      给出r×c的格子,上面有字符A和P。选择一个1×X的区域,指定某一方向与步长,该方向需与指定区域垂直;该方向的格子会被与起始指定区域同一行(列)的字符同化。问最少经过几次操作全部变成A

      模拟题。最多4步(或者不能),可以先判断能否3步的,其次2步,最后1步,节省代码量。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 
     6 char a[65][65];
     7 int t, w, h;
     8 
     9 bool judge(int x, int d) {
    10     if (d == 0) {
    11         inc(i, 0, w - 1) if (a[x][i] != 'A') return 0;
    12     } else {
    13         inc(i, 0, h - 1) if (a[i][x] != 'A') return 0;
    14     }
    15     return 1;
    16 }
    17 
    18 int main() {
    19     ios::sync_with_stdio(false);
    20     cin.tie(nullptr);
    21     cin >> t;
    22     while (t--) {
    23         cin >> h >> w;
    24         int all = 0;
    25         inc(i, 0, h - 1) {
    26             cin >> a[i];
    27             inc(j, 0, w - 1) all += a[i][j] == 'A';
    28         }
    29         if (all == 0)
    30             printf("MORTAL
    ");
    31         else if (all == h * w)
    32             printf("0
    ");
    33         else {
    34             int res = 4;
    35             inc(i, 1, h - 2) if (a[i][0] == 'A' || a[i][w - 1] == 'A') res = 3;
    36             inc(i, 1, w - 2) if (a[0][i] == 'A' || a[h - 1][i] == 'A') res = 3;
    37             inc(i, 1, h - 2) if (judge(i, 0)) res = 2;
    38             inc(i, 1, w - 2) if (judge(i, 1)) res = 2;
    39             if (a[0][0] == 'A' || a[0][w - 1] == 'A' || a[h - 1][0] == 'A' ||
    40                 a[h - 1][w - 1] == 'A')
    41                 res = 2;
    42             if (judge(0, 0) || judge(h - 1, 0) || judge(0, 1) ||
    43                 judge(w - 1, 1))
    44                 res = 1;
    45             printf("%d
    ", res);
    46         }
    47     }
    48 }
    View Code

     

    Jeremy Bearimy

      给出一个2n个点的树,两两匹配树上的所有节点,匹配后这些节点对的距离总和,问该距离总和的最小值与最大值。

      考虑以某一条边为界,把树分为两部分。要最大化距离总和时,要尽可能匹配不同部分的点,那么这条边就被计算min(sz, 2n-sz)次;,sz为一部分的节点数;要最小化距离总和时,要尽可能匹配同一部分的点,那么这条边就被计算 sz & 1 次。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 #define pii pair<int, int>
     6 #define fi first
     7 #define se second
     8 #define pb push_back
     9 
    10 const int maxn = 2e5 + 5;
    11 
    12 vector<pii> g[maxn];
    13 
    14 int t, n, u, v, dis;
    15 ll res1, res2;
    16 
    17 int dfs(int x, int par) {
    18     int sz = 1;
    19     for (int i = 0; i < g[x].size(); i++) {
    20         if (g[x][i].fi != par) {
    21             int t = dfs(g[x][i].fi, x);
    22             res1 += t % 2 * g[x][i].se;
    23             res2 += (ll)min(t, 2 * n - t) * g[x][i].se;
    24             sz += t;
    25         }
    26     }
    27     return sz;
    28 }
    29 
    30 int main() {
    31     ios::sync_with_stdio(false);
    32     cin.tie(nullptr);
    33     cin >> t;
    34     while (t--) {
    35         cin >> n;
    36         inc(i, 1, 2 * n) g[i].clear();
    37         inc(i, 1, 2 * n - 1) {
    38             cin >> u >> v >> dis;
    39             g[u].pb(pii(v, dis));
    40             g[v].pb(pii(u, dis));
    41         }
    42         res1 = res2 = 0;
    43         dfs(1, -1);
    44         printf("%lld %lld
    ", res1, res2);
    45     }
    46 }
    View Code

     

    Educational Codeforces Round 78 (Rated for Div. 2)

    Segment Tree

      给出n个区间,这些区间的端点取遍1-2n。当两个区间相交时(不能包含),它们代表的节点之间就有一条边。判断依此生成的图是否是树。

      对所有节点排序,遇到左端点加入set,遇到右端点时统计与其左端点间有多少个点,并删除左端点。用并查集维护集合关系。最后根据边数和连通性判断是否是树。因为每次都是遍历寻找左右端点间的点,此时算法的复杂度是O(n^2)。当统计点的个数大于n-1时,一定不是树,就可以break出来,此时是O(nlogn)。

    Tests for problem D

      给出n个节点的树,要为每一个节点构造一个区间,使得区间的左右端点取遍1-2n,两个节点之间是否有边等价于它们的区间是否相交(不能包含)。

      根的左端点为1,先序遍历,维护当前已使用的数字,当前区间的右端点贪心地取最小值——即右端点与已使用的数字之间的空余刚好能容下它的儿子的左端点(它的儿子的左端点就其次取这些空余的数字)。并且儿子的左端点越大越先遍历,这样可以保证儿子之间不会相交。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 #define inc(i, l, r) for (int i = l; i <= r; i++)
     5 #define pii pair<int, int>
     6 #define fi first
     7 #define se second
     8 #define pb push_back
     9 
    10 const int maxn = 1e6 + 5;
    11 
    12 vector<int> g[maxn];
    13 int n, u, v;
    14 pii res[maxn];
    15 
    16 int top = 1, root = 1;
    17 void dfs(int x, int par) {
    18     top += g[x].size();
    19     if (x == root) top++;
    20     res[x].se = top;
    21     for (int i = 0, j = 0; i < g[x].size(); i++) {
    22         if (g[x][i] != par) {
    23             res[g[x][i]].fi = top - ++j;
    24         }
    25     }
    26     for (int i = 0; i < g[x].size(); i++) {
    27         if (g[x][i] != par) {
    28             dfs(g[x][i], x);
    29         }
    30     }
    31 }
    32 
    33 int main() {
    34     ios::sync_with_stdio(false);
    35     cin.tie(nullptr);
    36     cin >> n;
    37     inc(i, 1, n - 1) {
    38         cin >> u >> v;
    39         g[u].pb(v);
    40         g[v].pb(u);
    41     }
    42     dfs(1, -1);
    43     res[1].fi = 1;
    44     inc(i, 1, n) cout << res[i].fi << " " << res[i].se << "
    ";
    45 }
    View Code
  • 相关阅读:
    iphone中button按钮显示为圆形解决
    获得URL含有中文出现乱码解决
    shell脚本检测监控mysql的CPU占用率
    centos6.x硬件信息统计脚本
    Linux下模拟多线程的并发并发shell脚本
    CentOS目录结构超详细版
    Centos 下搭建FTP上传下载服务器
    CentOS下输入输出重定向
    Centos时间查看修改命令date详解
    Shell脚本之awk详解
  • 原文地址:https://www.cnblogs.com/linqi05/p/12274138.html
Copyright © 2011-2022 走看看