zoukankan      html  css  js  c++  java
  • codeforces Educational Round 80


    A、Deadline

    题意:

    完成一个计划需要$d$天,但是可以优化,优化$x$天的情况下,完成时间是$x+lceil frac{d}{x+1} ceil$天。求$n$天内能否完成?

    题解:

    枚举天数即可,显然只需要枚举到$sqrt(d)$,如果可行马上输出。直接计算也可以,但是博主不会

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5 + 5;
     4 void solve()
     5 {
     6     int n, d;
     7     scanf("%d%d", &n, &d);
     8     for (int i = 0; i * i <= d; ++i)
     9     {
    10         int ans = 0;
    11         if (d % (i + 1))
    12             ans = d / (i + 1) + 1 + i;
    13         else
    14             ans = d / (i + 1) + i;
    15         if (n >= ans)
    16         {
    17             puts("YES");
    18             return;
    19         }
    20     }
    21     puts("NO");
    22 }
    23 int main()
    24 {
    25     int T;
    26     scanf("%d", &T);
    27     while (T--)
    28         solve();
    29     return 0;
    30 }
    View Code

    B、Yet Another Meme Problem

    题意:

    数字$a$范围在$[1,A]$,$b$范围在$[1,B]$,将$a$和$b$拼接起来,求这个数字等于$a*b+a+b$的值时,$a$和$b$取值的对数。

    题解:

    我们令$b$的位数是$k$,则$con(a,b) = a*10^k+b$,然后化简得$b=10^k-1$时即可。所以就找符合的$b$即可,此时$a$任意。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N = 1e5 + 5;
     5 void solve()
     6 {
     7     ll n, m;
     8     scanf("%lld%lld", &n, &m);
     9     ll cnt = 0;
    10     for (ll i = 10; i - 1 <= m; i *= 10)
    11         ++cnt;
    12     printf("%lld
    ", cnt * n);
    13 }
    14 int main()
    15 {
    16     int T;
    17     scanf("%d", &T);
    18     while (T--)
    19         solve();
    20     return 0;
    21 }
    View Code

    *C、Two Arrays

    题意:

    给出$n$和$m$,求出长度都是$m$的序列$a$和$b$,使得对于所有的$1 leq i leq m$:$a_i leq n, b_i leq n, a_i leq a_{i+1},b_i geq b_{i+1},a_i leq b_i$。

    题解:

    解法一、

    令$dp[i][j]$表示第$i$个数的$b_i-a_i=j$的方案数,转移方程:

    $dp[i][j] = sum limits _{k = j}^{n-1} dp[i-1][k]*(k-j+1)$

    可以使用前缀和优化,但是不优化也能过。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N = 1e3 + 5, M = 1e1 + 5;
     5 const ll mod = 1e9 + 7;
     6 ll dp[M][N], sum[N];
     7 void solve()
     8 {
     9     int n, m;
    10     scanf("%d%d", &n, &m);
    11     for (int i = 0; i < n; ++i)
    12         dp[1][i] = n - i;
    13     for (int i = 2; i <= m; ++i)
    14         for (int j = 0; j < n; ++j)
    15             for (int k = j; k < n; ++k)
    16                 dp[i][j] = (dp[i][j] + dp[i - 1][k] * (k - j + 1)) % mod;
    17     ll ans = 0;
    18     for (int i = 0; i < n; ++i)
    19         ans = (ans + dp[m][i]) % mod;
    20     printf("%lld
    ", ans);
    21 }
    22 int main()
    23 {
    24     int T = 1;
    25     //scanf("%d", &T);
    26     while (T--)
    27         solve();
    28     return 0;
    29 }
    View Code

    解法二、

    官方题解的做法,反正我是惊呆了。

    考虑长度是$2*m$的序列$a_1,a_2,...,a_m,b_m,...b_2,b_1$,这个序列是单调不降的,等价于从$1$到$n$中选择$2*m$个数组成的可重集的数量的和。所以答案就是$C_{n+2*m-1}^{2*m}$

    取模求个逆元就行。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N = 1.1e3 + 5;
     5 const ll mod = 1e9 + 7;
     6 ll pow(ll a, ll b, ll p)
     7 {
     8     ll res = 1;
     9     while (b)
    10     {
    11         if (b & 1)
    12             res = res * a % p;
    13         a = a * a % p;
    14         b >>= 1;
    15     }
    16     return res;
    17 }
    18 ll fac[N];
    19 void solve()
    20 {
    21     fac[0] = 1;
    22     for (int i = 1; i < N; ++i)
    23         fac[i] = fac[i - 1] * i % mod;
    24     int n, m;
    25     scanf("%d%d", &n, &m);
    26     printf("%lld
    ", fac[n + 2 * m - 1] * pow(fac[n - 1], mod - 2, mod) % mod * pow(fac[2 * m], mod - 2, mod) % mod);
    27 }
    28 int main()
    29 {
    30     int T = 1;
    31     //scanf("%d", &T);
    32     while (T--)
    33         solve();
    34     return 0;
    35 }
    View Code

    *D、Minimax Problem

    题意:

    给出$n$行$m$列的矩阵,$n leq 3e5,m leq 8$。求两行(可以一样),使得$min(max _{1leq i leq m} (a_i, b_i))$最大。

    题解:

    使最小值最大,必然先考虑二分答案。但是我们要怎么验证?注意到二分的答案的含义是:存在一个选法使得结果大于这个答案,那么取右半,否则取左半。如果$a_i$和$b_i$只要有一个大于这个答案,$max$就大于这个答案,所以考虑把大于等于设成$1$,否则设成$0$,然后状压。将每一列变成一个$[0.255]$的数,然后相当于是找两个数,使得$c_i | c_j = 2^m-1$,暴力找时间复杂度不对,考虑剪枝:如果一个数本身就是$2^m-1$,直接返回,如果一个数是$0$跳过。还可以建图寻找,但是实际上使用剪枝即可通过。注意!如果最终找不到大于$0$的答案,输出$1 1$。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 3e5 + 5;
     4 int n, m, px, py;
     5 int a[N][15];
     6 int buc[305];
     7 bool check(int x)
     8 {
     9     memset(buc, 0, sizeof(buc));
    10     for (int i = 1; i <= n; ++i)
    11     {
    12         int tmp = 0;
    13         for (int j = 1; j <= m; ++j)
    14             tmp |= (a[i][j] >= x) << (j - 1);
    15         buc[tmp] = i;
    16     }
    17     for (int i = 0; i < (1 << m); ++i)
    18         for (int j = 0; j < (1 << m); ++j)
    19             if (buc[i] && buc[j] && (i | j) == (1 << m) - 1)
    20             {
    21                 px = buc[i], py = buc[j];
    22                 return true;
    23             }
    24     return false;
    25 }
    26 void solve()
    27 {
    28     scanf("%d%d", &n, &m);
    29     for (int i = 1; i <= n; ++i)
    30         for (int j = 1; j <= m; ++j)
    31             scanf("%d", &a[i][j]);
    32     int l = 0, r = 1e9 + 5;
    33     while (l < r)
    34     {
    35         int m = (l + r) >> 1;
    36         if (!check(m))
    37             r = m;
    38         else
    39             l = m + 1;
    40     }
    41     if (!l)
    42         printf("1 1
    ");
    43     else
    44         printf("%d %d
    ", px, py);
    45 }
    46 int main()
    47 {
    48     int T = 1;
    49     //scanf("%d", &T);
    50     while (T--)
    51         solve();
    52     return 0;
    53 }
    View Code

    E、Messenger Simulator

    题意:

    给出一个$n$个人的序列,编号$1~n$,和$m$次操作,每次操作可以让一个人到最前面,然后他前面的人往后退一个人,求这个过程中每个人最前和最后的位置。

    题解:

    这不是$splay$裸题吗

    这个题目实际上就是查找树节点在第$k$大和插入到最左边。所以$splay$可做,但是太麻烦,没必要。

    求第$k$大可以用树状数组或者权值线段树,然后考虑到这些数都是往最前面移,所以后面移动的一定在前面移动的前面,所以就建立一棵大小是$m+n$的树状数组,后$n$个数置为$1$,前$m$个数置为$0$,记录初始序列人的位置是$pos[a_i] = m+i$,然后第$i$次操作,就先统计一下当前需要操作的结点的第$k$大,然后移到$m-i+1$,更新$pos$数组,在所有操作完成后再更新一次所有位置即可。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 3e5 + 5;
     4 struct BIT
     5 {
     6     int c[N << 1];
     7     void update(int pos, int n, int v)
     8     {
     9         for (; pos <= n; pos += pos & (-pos))
    10             c[pos] += v;
    11     }
    12     int query(int pos)
    13     {
    14         int res = 0;
    15         for (; pos; pos -= pos & (-pos))
    16             res += c[pos];
    17         return res;
    18     }
    19 };
    20 BIT tr;
    21 pair<int, int> ans[N];
    22 int pos[N];
    23 void solve()
    24 {
    25     memset(tr.c, 0, sizeof(tr.c));
    26     int n, m, a;
    27     scanf("%d%d", &n, &m);
    28     for (int i = 1; i <= n; ++i)
    29         ans[i] = {i, i}, pos[i] = m + i;
    30     for (int i = m + 1; i <= m + n; ++i)
    31         tr.update(i, m + n, 1);
    32     for (int i = 1; i <= m; ++i)
    33     {
    34         scanf("%d", &a);
    35         int p = pos[a];
    36         ans[a].second = max(ans[a].second, tr.query(p));
    37         ans[a].first = 1;
    38         tr.update(p, m + n, -1);
    39         pos[a] = m + 1 - i;
    40         tr.update(pos[a], m + n, 1);
    41     }
    42     for (int i = 1; i <= n; ++i)
    43         ans[i].second = max(ans[i].second, tr.query(pos[i]));
    44     for (int i = 1; i <= n; ++i)
    45         printf("%d %d
    ", ans[i].first, ans[i].second);
    46 }
    47 int main()
    48 {
    49     int T = 1;
    50     //scanf("%d", &T);
    51     while (T--)
    52         solve();
    53     return 0;
    54 }
    View Code
  • 相关阅读:
    如何在 Linux 虚拟机上扩展根文件系统
    Linux 虚拟机中配置 GNOME + VNC
    在 Linux 中使用 Azure Premium 存储的基本优化指南
    如何为运行的 ARM Linux 启用 LAD2.3 版本的诊断扩展
    不要在构造函数中抛出异常
    vtk java
    富文本keditor的一些使用问题
    几个问题
    Java并发编程(十四)并发容器类
    FreeBSD编译安装emacs,不要用ports
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/13233431.html
Copyright © 2011-2022 走看看