• codeforces Round 647(div. 2)



    A、Johnny and Ancient Computer

    题意:

    给出$x$和$y$,每次只能$x$乘$8$,乘$4$,乘$2$,除$2$,除$4$,除$8$,选一个操作,求$x$变成$y$的最小操作次数。

    题解:

    首先我们先假定$x<y$,然后把它们表示成$r_1 imes 2^{e_1}$,$r_2 imes 2^{e_2}$,必须有$r_1=r_2$,在这个前提下,$x$不断乘$8$到下一次乘$8$大于$y$了,然后如果$x$最终等于$y$了,乘的次数就是答案。否则$x$一定可以乘$4$或者$2$使得$x=y$,这样子就次数$+1$就是答案。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 int get(ll a)
     5 {
     6     while (a % 2 == 0)
     7         a /= 2;
     8     return a;
     9 }
    10 void solve()
    11 {
    12     ll a, b;
    13     scanf("%lld%lld", &a, &b);
    14     if (a > b)
    15         swap(a, b);
    16     if (get(a) != get(b))
    17     {
    18         printf("-1
    ");
    19         return;
    20     }
    21     b /= a;
    22     int ans = 0;
    23     while (b && b % 8 == 0)
    24         ++ans, b /= 8;
    25     if (b > 1)
    26         ++ans;
    27     printf("%d
    ", ans);
    28 }
    29 int main()
    30 {
    31     int T;
    32     scanf("%d", &T);
    33     while (T--)
    34         solve();
    35     return 0;
    36 }
    View Code

    (黑科技:$OEIS$有公式,可以直接查)

    B、Johnny and His Hobbies

    题意:

    给出一个集合,求能不能找到一个正数,使得这个集合中的所有数异或后的值组成的新集合,原集合一样。$sum sizeleq 1024,s_ileq 1024$。

    题解:

    这个没啥规律的$QAQ$,直接暴力找就行了,上界是$1023$。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 set<int> s;
     5 void solve()
     6 {
     7     s.clear();
     8     int n, a;
     9     scanf("%d", &n);
    10     for (int i = 1; i <= n; ++i)
    11     {
    12         scanf("%d", &a);
    13         s.insert(a);
    14     }
    15     set<int> t;
    16     int maxn = *(--s.end());
    17     int ans = -1;
    18     for (int i = 1; i < (1 << 10); ++i)
    19     {
    20         t.clear();
    21         for (auto &j : s)
    22             t.insert(i ^ j);
    23         if (s == t)
    24         {
    25             ans = i;
    26             break;
    27         }
    28     }
    29     printf("%d
    ", ans);
    30 }
    31 int main()
    32 {
    33     int T;
    34     scanf("%d", &T);
    35     while (T--)
    36         solve();
    37     return 0;
    38 }
    View Code

    C、Johnny and Another Rating Drop

    题意:

    给出$x$,求出从$0$到$x$的相邻数字二进制串的汉明距离和。

    题解:

    写出$1$,$2$,$3$,$4$,......,$16$的结果,然后可以找到规律,如果二进制串中某一位是$1$,结果就一定会加上一个定值,并且这个定值有规律,打个表然后查表就行了。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef unsigned long long ll;
     4 ll num[80];
     5 void init()
     6 {
     7     num[0] = 1;
     8     for (int i = 1; i <= 64; ++i)
     9         num[i] = num[i - 1] + (1ull << i);
    10 }
    11 void solve()
    12 {
    13     ll n;
    14     scanf("%llu", &n);
    15     ll ans = 0;
    16     for (int i = 0; n; n >>= 1, ++i)
    17         if (n & 1)
    18             ans += num[i];
    19     printf("%llu
    ", ans);
    20 }
    21 int main()
    22 {
    23     init();
    24     int T;
    25     scanf("%d", &T);
    26     while (T--)
    27         solve();
    28     return 0;
    29 }
    View Code

    D、Johnny and Contribution

    题意:

     给出$n$的点的图,每个点有一种颜色,初始都没有涂色,求出一个涂色顺序,使得当前涂色的这个点的颜色必须是已经涂色的点的集合的$mex$,如果没有输出$-1$。

    题解:

    而且我们限定涂色顺序是从小的颜色到大的颜色。如果没有$1$直接$-1$。然后给它的邻接点更新连续数的$max$,这样子到了涂这个点的时候,它的颜色必须是$max+1$,然后再更新邻接点,否则$-1$。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 5e5 + 5;
     4 vector<int> G[N];
     5 struct node
     6 {
     7     int v, id;
     8     bool operator<(const node &a) const
     9     {
    10         return id == a.id ? v < a.v : id < a.id;
    11     }
    12 };
    13 int maxn[N];
    14 node e[N];
    15 vector<int> ans;
    16 int main()
    17 {
    18     int n, m;
    19     scanf("%d%d", &n, &m);
    20     for (int i = 1; i <= m; ++i)
    21     {
    22         int u, v;
    23         scanf("%d%d", &u, &v);
    24         G[u].push_back(v);
    25         G[v].push_back(u);
    26     }
    27     for (int i = 1; i <= n; ++i)
    28     {
    29         scanf("%d", &e[i].id);
    30         e[i].v = i;
    31     }
    32     for (int i = 1; i <= n; ++i)
    33         for (auto j : G[i])
    34             if (e[i].id == e[j].id)
    35                 return printf("-1
    "), 0;
    36     sort(e + 1, e + n + 1);
    37     for (int i = 1; i <= n; ++i)
    38     {
    39         int v = e[i].v;
    40         if (e[i].id == maxn[v] + 1)
    41         {
    42             maxn[v] = e[i].id;
    43             ans.push_back(v);
    44             for (auto u : G[v])
    45                 if (maxn[v] == maxn[u] + 1)
    46                     maxn[u] = maxn[v];
    47         }
    48         else
    49             return printf("-1
    "), 0;
    50     }
    51     for (int i = 0; i < ans.size(); ++i)
    52         printf("%d%c", ans[i], " 
    "[i == ans.size() - 1]);
    53     return 0;
    54 }
    View Code

    E、Johnny and Grandmaster

    题意:

    给出$n$个数,$p$,把这个$n$个数分成两个多重集合$s_1,s_2$。求$abs(sum limits _{i in s_1} p^{i}-sum limits _{i in s_2} p^{i})$最小。

    题解:

    解法一:

    考虑把这$n$个数降序排序,初始的答案是$0$,然后考虑如果当前答案是$0$就加上当前数,否则减去当前数,因为要$mod (1e9+7)$,所以实际上变成当前初始答案$0$之后,差不一定是$0$,可能是模数的倍数,这样子,如果我们使用多模数哈希,只有这些模数都是$0$的时候,我们认为这个和确实到$0$了,然后最后输出模数是$1e9+7$的答案即可。为了尽量减小错误概率,模数必须是素数且尽量接近$1e9+7$,实际上只用$1e9+7$和$1e9+3$即可通过本题。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e6 + 5;
     4 const int mod = 1e9 + 7;
     5 const int mod1 = 1e9 + 3;
     6 typedef long long ll;
     7 int a[N];
     8 ll qpow(ll a, ll b, ll p)
     9 {
    10     ll res = 1;
    11     while (b)
    12     {
    13         if (b & 1)
    14             res = res * a % p;
    15         a = a * a % p;
    16         b >>= 1;
    17     }
    18     return res;
    19 }
    20 void solve()
    21 {
    22     int n, p;
    23     scanf("%d%d", &n, &p);
    24     for (int i = 1; i <= n; ++i)
    25         scanf("%d", &a[i]);
    26     sort(a + 1, a + n + 1, greater<int>());
    27     ll ans1 = 0, ans2 = 0;
    28     for (int i = 1; i <= n; ++i)
    29     {
    30         if (!ans1 && !ans2)
    31         {
    32             ans1 = (ans1 + qpow(p, a[i], mod)) % mod;
    33             ans2 = (ans2 + qpow(p, a[i], mod1)) % mod1;
    34         }
    35         else
    36         {
    37             ans1 = (ans1 - qpow(p, a[i], mod) + mod) % mod;
    38             ans2 = (ans2 - qpow(p, a[i], mod1) + mod1) % mod1;
    39         }
    40     }
    41     printf("%lld
    ", (ans1 + mod) % mod);
    42     return;
    43 }
    44 int main()
    45 {
    46     int T;
    47     scanf("%d", &T);
    48     while (T--)
    49         solve();
    50     return 0;
    51 }
    View Code

    解法二:

    继续先降序排序,然后也还是加减的操作,只不过这里我们发现对于$p^k$,减的时候,一定会经过$0$,而不是直接从正减到负,同时,这个差一定能表示成$a imes p^b$。所以我们只需要保存$a$和$b$即可。然后考虑到这$n$个数的上界是$1e6$,如果$a$已经大于$1e6$了或者小于$-1e6$了,显然我们已经没有办法,让这个$a$回到$0$,这个时候直接让$a$是$1e6$或者$-1e6$即可,因为这个情况下,显然后面所有的数都应该减。实际上这个$1e6$是一个设置的上界而已,你也可以设置成$1e8$。

    AC代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e6 + 5;
     4 const int mod = 1e9 + 7;
     5 typedef long long ll;
     6 const ll INF = 1e6;
     7 ll qpow(ll a, ll b, ll p)
     8 {
     9     ll res = 1;
    10     while (b)
    11     {
    12         if (b & 1)
    13             res = res * a % p;
    14         a = a * a % p;
    15         b >>= 1;
    16     }
    17     return res;
    18 }
    19 int a[N];
    20 int nowk, n;
    21 ll dif, p, ans;
    22 inline void cal(int x)
    23 {
    24     ans = ans * qpow(p, nowk - x, mod) % mod;
    25     if (dif)
    26         for (int i = 1; i <= nowk - x; ++i)
    27         {
    28             dif = max(min(dif * p, INF), -INF);
    29             if (dif == 1e6 || dif == -1e6)
    30                 break;
    31         }
    32     nowk = x;
    33 }
    34 inline void push(int x)
    35 {
    36     cal(x);
    37     if (dif > 0)
    38         --ans, --dif;
    39     else
    40         ++ans, ++dif;
    41 }
    42 void solve()
    43 {
    44     scanf("%d%lld", &n, &p);
    45     for (int i = 1; i <= n; ++i)
    46         scanf("%d", &a[i]);
    47     sort(a + 1, a + n + 1, greater<int>());
    48     if (p == 1)
    49     {
    50         printf("%d
    ", n % 2);
    51         return;
    52     }
    53     ans = dif = 0;
    54     nowk = N;
    55     for (int i = 1; i <= n; ++i)
    56         push(a[i]);
    57     cal(0);
    58     printf("%lld
    ", (ans + mod) % mod);
    59 }
    60 int main()
    61 {
    62     int T;
    63     scanf("%d", &T);
    64     while (T--)
    65         solve();
    66     return 0;
    67 }
    View Code
  • 相关阅读:
    互联网原理
    正则表达式
    BOM对象
    事件
    DOM对象
    已有项目安装脚手架工具vite
    小程序订阅消息 多个模板id
    百度地图 InfoWindow上添加点击事件
    颜色渐变 Echarts 环形图
    js替换字符串中所有斜杠
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/13096383.html
Copyright © 2020-2023  润新知