• Codeforces Round #513 (rated, Div. 1 + Div. 2)


    前记

    眼看他起高楼;眼看他宴宾客;眼看他楼坍了。

    比赛历程

    开考前一分钟还在慌里慌张地订正上午考试题目。

    “诶这个数位dp哪里见了鬼了???”瞥了眼时间,无奈而迅速地关去所有其他窗口,临时打了一个缺省源。

    A. Phone Numbers

    那么就是模拟。

     1 #include<bits/stdc++.h>
     2 
     3 int n,x;
     4 char s[103];
     5 
     6 int read()
     7 {
     8     char ch = getchar();
     9     int num = 0;
    10     bool fl = 0;
    11     for (; !isdigit(ch); ch=getchar())
    12         if (ch=='-') fl = 1;
    13     for (; isdigit(ch); ch=getchar())
    14         num = (num<<1)+(num<<3)+ch-48;
    15     if (fl) num = -num;
    16     return num;
    17 }
    18 int main()
    19 {
    20     n = read();
    21     scanf("%s",s);
    22     for (int i=0; i<n; i++)
    23         if (s[i]=='8') x++;
    24     printf("%d
    ",std::min(x, n/11));
    25     return 0;
    26 }

    B. Maximum Sum of Digits

    结论题。构造尽可能多的999……

     1 #include<bits/stdc++.h>
     2 typedef long long ll;
     3 
     4 ll n,num;
     5 
     6 long long read()
     7 {
     8     char ch = getchar();
     9     long long num = 0;
    10     bool fl = 0;
    11     for (; !isdigit(ch); ch=getchar())
    12         if (ch=='-') fl = 1;
    13     for (; isdigit(ch); ch=getchar())
    14         num = (num<<1)+(num<<3)+ch-48;
    15     if (fl) num = -num;
    16     return num;
    17 }
    18 ll calc(ll x)
    19 {
    20     ll ret=0;
    21     for (; x; x/=10) ret += x%10;
    22     return ret;
    23 }
    24 int main()
    25 {
    26     n = read(), num = 0;
    27     while (num < n) num = num*10+9;
    28     num /= 10;
    29     printf("%lld
    ",calc(num)+calc(n-num));
    30     return 0;
    31 }

    C. Maximum Subrectangle

    有点意思的题:找一个面积最大,权值和小于lim的矩阵。但是这个矩阵有个特殊性质:它不是没有规律地给定,而是由两个数列相乘构造而来。n<=2000.

    做法一:

    先枚举一个维,将这个维所有的段长和元素和都存下来,然后sort一下。另一维枚举,二分寻找最大能够匹配的段。

    时间复杂度$O(n^2log_2n)$

    做法二:

    然而上面一个做法的浪费在于存下所有的段。注意到这个决策是单调的,对于长度相同的段,只有元素和最小的是有用的。那么对于两个维,都记录这个最小值。最后分别枚举两维的长度时直接匹配。

    时间复杂度$O(n^2)$

     1 #include<bits/stdc++.h>
     2 const int maxn = 2035;
     3 
     4 struct node
     5 {
     6     int a,b;
     7     bool operator < (node x) const
     8     {
     9         if (a < x.a) return a < x.a;
    10         return b < x.b;
    11     }
    12 }sv[6000035];
    13 int a[maxn],b[maxn],n,m,lim;
    14 int sa[maxn],sb[maxn];
    15 int mna[maxn],mnb[maxn];
    16 int cnt,ans;
    17 
    18 int read()
    19 {
    20     char ch = getchar();
    21     int num = 0;
    22     bool fl = 0;
    23     for (; !isdigit(ch); ch=getchar())
    24         if (ch=='-') fl = 1;
    25     for (; isdigit(ch); ch=getchar())
    26         num = (num<<1)+(num<<3)+ch-48;
    27     if (fl) num = -num;
    28     return num;
    29 }
    30 int main()
    31 {
    32     memset(mna, 0x3f3f3f3f, sizeof mna);
    33     memset(mnb, 0x3f3f3f3f, sizeof mnb);
    34     n = read(), m = read();
    35     for (int i=1; i<=n; i++) a[i] = read(), sa[i] = sa[i-1]+a[i];
    36     for (int i=1; i<=m; i++) b[i] = read(), sb[i] = sb[i-1]+b[i];
    37     lim = read();
    38     for (int i=1; i<=n; i++)
    39         for (int j=i; j<=n; j++)
    40             mna[j-i+1] = std::min(mna[j-i+1], sa[j]-sa[i-1]);
    41     for (int i=1; i<=m; i++)
    42         for (int j=i; j<=m; j++)
    43             mnb[j-i+1] = std::min(mnb[j-i+1], sb[j]-sb[i-1]);
    44     for (int i=1; i<=n; i++)
    45         for (int j=1; j<=m; j++)
    46             if (1ll*mna[i]*mnb[j] <= 1ll*lim)
    47                 ans = std::max(ans, i*j);
    48     printf("%d
    ",ans);
    49     return 0;
    50 }

    D. Social Circles

    开场时候原本就打算手速D的,又恰巧总榜上D被秒掉了。于是弃了BC就去看D……

    想了好久也没有什么靠谱做法,这时t老师6分钟就写完了D,瞬间心态崩坏。

    想啊想啊,是个贪心?图论?然而一点没往结论题方向想。

    没办法只能转回头去做C。脑子里一团浆糊,什么也想不进去。

    最后是等到XCW在1:09大力猜结论过了pretest机房才大队人马过D。

    大致题意:有n个人,每个人要求自己左边有li张空椅子;右边有ri张空椅子。可以把不同的人任意分组。问最小需要的总椅子数量。

    结论是:这些人的左右手要求是可以互换的。那么就是排序之后取max。

    好像现在官方题解还没出来?那么这个结论我也没法证明……

     1 #include<bits/stdc++.h>
     2 const int maxn = 100035;
     3 
     4 int n,a[maxn],b[maxn];
     5 long long ans;
     6 
     7 int main()
     8 {
     9     scanf("%d",&n);
    10     for (int i=1; i<=n; i++) scanf("%d",&a[i]);
    11     for (int i=1; i<=n; i++) scanf("%d",&b[i]);
    12     std::sort(a+1, a+n+1);
    13     std::sort(b+1, b+n+1);
    14     for (int i=1; i<=n; i++) ans += std::max(a[i], b[i]);
    15     printf("%lld
    ",ans);
    16     return 0;
    17 }

    E. Sergey and Subway

    花CD的时间太久了……E题题意直接去问同学了。

    然而刚开始一段时间把题意理解错了。

    大致题意:现在有一颗树,边权均为1。每次操作将原树上距离为2的点,在新树上连接一条边权为1的边。进行操作直到不能再操作为止。询问新树两两点对距离和。

    首先是结论:原树上长度为$d$的路径,在新树上长度变为$frac{d+1}{2}(向下取整)$。

    这个比较容易理解:对于长度为2的路径,长度变为1;长度为1的路径,长度不变;然后任意一条路径都可以视作由2、1的路径拼接而成。

    第一感觉是点分?但是一看时间不大对了直接去求助t老师了。

    t老师:不用点分……一开始我写了一个很复杂的上下dp。这个题超傻逼的,只要枚举边计算贡献。然后计奇数路径条数。深度奇偶性不同的就是奇数路径。

    哇好有道理的样子哦。想了想就开始码(然而中间还码错了点小细节耽搁一会),然后就愉快地过掉了。(但是毕竟还是手速太慢,E题最后只有1008的分)

     1 #include<bits/stdc++.h>
     2 const int maxn = 200035;
     3 
     4 long long ans;
     5 int n,tot[maxn],dep[maxn],sum[3];
     6 int edges[maxn<<1],nxt[maxn<<1],head[maxn],edgeTot;
     7 
     8 int read()
     9 {
    10     char ch = getchar();
    11     int num = 0;
    12     bool fl = 0;
    13     for (; !isdigit(ch); ch=getchar())
    14         if (ch=='-') fl = 1;
    15     for (; isdigit(ch); ch=getchar())
    16         num = (num<<1)+(num<<3)+ch-48;
    17     if (fl) num = -num;
    18     return num;
    19 }
    20 void addedge(int u, int v)
    21 {
    22     edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
    23     edges[++edgeTot] = u, nxt[edgeTot] = head[v], head[v] = edgeTot;
    24 }
    25 void dfs(int x, int fa)
    26 {
    27     tot[x] = 1, dep[x] = dep[fa]+1, sum[dep[x]&1]++;
    28     for (int i=head[x]; i!=-1; i=nxt[i])
    29     {
    30         int v = edges[i];
    31         if (v!=fa){
    32             dfs(v, x);
    33             tot[x] += tot[v];
    34             long long t = 1ll*tot[v]*(n-tot[v]);
    35             ans += t;
    36         }
    37     }
    38 }
    39 int main()
    40 {
    41     memset(head, -1, sizeof head);
    42     n = read();
    43     for (int i=1; i<n; i++) addedge(read(), read());
    44     dfs(1, 1);
    45     ans += 1ll*sum[0]*sum[1];
    46     printf("%lld
    ",ans/2);
    47     return 0;
    48 }

    xor则是发现了点分FFT的写法,恰巧以前度教出过一道类似的题,于是机房大队人马搬来自己代码争先恐后地过了pretest。

    【后话:除了我和xor其他人都FST了;反正WA、RE、TLE全齐了】

    后记

    哎,暑假一共就打了两场,打得还非常差。现在也不过是一直在expert徘徊。

    反观同级甚至初中的大佬,已经不是Grandmaster就是Master最差Candiate Master了。

    考试时候依然起伏不定,思维发挥也没有达到所期望的那种地步。

    即便是往年今日,zx2003也早就上紫了啊!

    “How BAD do you want it?”

  • 相关阅读:
    c#: 传不确定个数参的方法
    导出Excel并设置样式
    无线网络国际会议排名
    初学Java接口
    初学Java修饰符
    [转]计算机类核心期刊投稿的一些资料汇总
    初学Java数据类型和变量
    初学Java数组
    初学Java运算符
    几个著名P2P会议与期刊及领军人物
  • 原文地址:https://www.cnblogs.com/antiquality/p/9743552.html
Copyright © 2020-2023  润新知