A - Happy Birthday, Polycarp!
题意:给一个n<=1e9,求[1,n]里面有多少个数字是有单个数字重复多次构成的。
题解:这种数字本身不对,一个一个暴力验证就可以。假如数据量继续扩大,那么把所有的数字生成出来(至多200个,当1e18时),排个序,然后把n在里面二分,应该速度会大概提升10倍。
void test_case() {
int n, ans = 0;
scanf("%d", &n);
for(int x = 1; x <= 9; ++x) {
ll tmp = x;
while(tmp <= n) {
++ans;
tmp = 10 * tmp + x;
}
}
printf("%d\n", ans);
}
B - Make Them Odd
题意:给一个序列,你每次可以选一个偶数,然后把所有等于这个偶数的数变成原来的一半,求最小的操作步数。
题解:每次取最大的出来贪心,每个数最多被贪30次,再加上优先队列的log就不太美妙了,但是总的复杂度依然是nlogn+nlogai。经过观察发现能够连在一起的都是非2的部分一样的数,也就是每种除去2的幂之后一样的数贡献这一种的最高2的幂,还是要用map去统计,复杂度没变。
附带一个更快的分解2的幂次的办法:__builtin_ctz(x),返回后跟0的数量。来源:https://www.cnblogs.com/liuzhanshan/p/6861596.html
int a[200005];
map<int, int> m;
void test_case() {
int n, ans = 0;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
int tmp = __builtin_ctz(a[i]);
m[a[i] >> tmp] = max(m[a[i] >> tmp], tmp);
}
for(auto &i : m)
ans += i.second;
m.clear();
printf("%d\n", ans);
}