A.Johnny and Ancient Computer
题意:
给出和
,每次只能进行
选一个操作,求变成
的最小操作次数。
题解:
因为乘除等价,直接贪心判断即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
const int INF = 0x3f3f3f3f;
void solve()
{
ll x, y;
scanf("%lld%lld", &x, &y);
if(x > y) swap(x, y);
int ans = 0;
while(x<y)
{
if(8 * x <= y)
x *= 8, ans++;
else if(4 * x <= y)
x *= 4, ans++;
else if(2 * x <= y)
x *= 2, ans++;
else break;
}
printf("%d\n",x == y ? ans : -1);
}
int main()
{
int t;
for (scanf("%d", &t); t >= 1; t--)
solve();
return 0;
}
B.Johnny and His Hobbies
题意:
问最小的数字使得初始集合的每个数
都异或
后集合不变。
题解:
因为,因此
,所以只需要贪心从小到大遍历
中满足条件的值输出最小的即可,否则输出
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
void solve()
{
int n;
scanf("%d", &n);
set<int> s;
for (int i = 0, x; i < n; i++)
scanf("%d", &x), s.insert(x);
for (int i = 1; i <= 1024; i++)
{
set<int> t;
for (auto j : s)
t.insert(j ^ i);
if (s == t)
{
printf("%d\n", i);
return;
}
}
puts("-1");
}
int main()
{
int t;
for (scanf("%d", &t); t >= 1; t--)
solve();
} C.Johnny and Another Rating Drop
题意:
给定一个数,定义两个数的差值是二进制下不同的位数。求
到
相邻数字的差值之和。
题解:
观察样例可以发现答案就是每位上
的个数之和
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
void solve()
{
ll n;
scanf("%lld", &n);
ll ans = 0;
while (n)
{
ans += n;
n /= 2;
}
printf("%lld\n", ans);
}
int main()
{
int t;
for (scanf("%d", &t); t >= 1; t--)
solve();
} D.Johnny and Contribution
题意:
给定一张图,每一个节点都是一篇博客,每个点的主题数是除周围博客主题数之外数的最小值。询问是否存在一种符合期望的主题数的访问顺序。
题解:
根据每个顶点的属性从小到大进行排序。然后依次安排,对每个节点判断一下相邻结点
的期望颜色是否也为与
颜色相同,如果是,则
的期望颜色加一.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 5;
int num[maxn];
vector<int> G[maxn], col[maxn], ans;
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i <= m; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
for (int i = 1, x; i <= n; i++)
{
scanf("%d", &x);
col[x].push_back(i);
num[i] = 1;
}
for (int i = 1; i <= n; i++)
{
for (auto u : col[i])
{
if (num[u] != i)
{
puts("-1");
return 0;
}
for (auto v : G[u])
if (num[v] == i)
num[v]++;
ans.push_back(u);
}
}
for (auto i : ans)
printf("%d ", i);
puts("");
return 0;
} E.Johnny and Grandmaster
题意:
给定个数
和底数
,可以获得
个贡献
,把这
个贡献分成两份,询问两份的最小差值的绝对值是多少?
题解:
把这个数从大到小进行排序,对于每个数,如果把这个数分配给一个集合,那么另外一个集合就要想办法凑出这个数。此时有两种情况:
- 剩下所有数拿完,还不能大于第一堆,那答案就是他们的差值。
- 剩下所有数的和大于第一堆那个数,如果是这个情况那么我们必定能拿到一些数,使得他们的和要等于第一堆那个数,然后两者抵消,再判断剩下那些数就行。
要注意的是差值为的时候 不能光用
来判断,得再搞一个模数来保证差值为
,因为当差值为
的倍数时,结果也同样为
,但实际不为
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
const ll mod1 = 1e9 + 7;
const ll mod2 = 983231753;
ll k[maxn];
ll ksm(ll a, ll b, ll mod)
{
ll ans = 1;
while (b)
{
if (b & 1)
ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
void solve()
{
ll n, p;
scanf("%lld%lld", &n, &p);
for (ll i = 1; i <= n; i++)
scanf("%lld", &k[i]);
ll ans1 = 0, ans2 = 0;
sort(k + 1, k + n + 1, greater<ll>());
for (ll i = 1; i <= n; i++)
{
ll t1 = ksm(p, k[i], mod1);
ll t2 = ksm(p, k[i], mod2);
if (ans1 == 0 && ans2 == 0)
ans1 = t1, ans2 = t2;
else
ans1 = (ans1 - t1 + mod1) % mod1, ans2 = (ans2 - t2 + mod2) % mod2;
}
printf("%lld\n", ans1);
}
int main()
{
int t;
for (scanf("%d", &t); t >= 1; t--)
solve();
} 
京公网安备 11010502036488号