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
原文地址:https://www.cnblogs.com/Aya-Uchida/p/13096383.html