Codeforces Round #694 (Div. 2)
Codeforces Round #694 (Div. 2)
熬夜逆向上分
A. Strange Partition
\(\lceil \frac{a+b}{x} \rceil <= \lceil \frac{a}{x} \rceil + \lceil \frac{b}{x} \rceil\)
所以最大的时候肯定是初始状态,最小的时候肯定是全加起来的时候。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int t;
scanf("%d", &t);
while(t--) {
int n, x;
scanf("%d%d", &n, &x);
LL max_num = 0, min_num = 0;
for (int i = 1; i <= n; i++) {
int p;
scanf("%d", &p);
max_num += p / x + (p % x != 0);
min_num += p;
}
min_num = min_num / x + (min_num % x != 0);
printf("%lld %lld\n", min_num, max_num);
}
}
B. Strange List
一个数被拆掉,拆出来的数字之和(贡献)还是等于这个数。
如果把一个数拆出来的数叫做 衍生数,那就看哪个数的衍生数先拆不掉就好了。
能拆掉就把这个衍生数对应的初始数加入答案,不能拆掉就结束程序。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 10;
int a[MAXN], b[MAXN];
int n, x;
LL get_ans() {
LL ans = 0;
for (int i = 1; i <= n; i++) {
ans += a[i];
}
while(true) {
for (int i = 1; i <= n; i++) {
if (b[i] % x == 0) {
ans += a[i];
b[i] /= x;
} else {
return ans;
}
}
}
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &x);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
b[i] = a[i];
}
printf("%lld\n", get_ans());
}
}
C. Strange Birthday Party
因为可以用钱招待(打发)客人,所以把客人按照钱从大到小排序,能给玩具就给玩具,不能给的用钱招待(打发)。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 3e5 + 10;
int a[MAXN], p[MAXN];
bool cmp(int x, int y) {
return p[x] > p[y];
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= m; i++) {
scanf("%d", &p[i]);
}
sort(a+1, a+1+n);
reverse(a+1, a+1+n);
int tag = 1;
LL ans = 0;
for (int i = 1; i <= n; i++) {
if (tag < a[i]) {
ans += p[tag++];
} else {
ans += p[a[i]];
}
}
printf("%lld\n", ans);
}
}
D. Strange Definition
\(\frac{lcm(x, y)}{gcd(x, y)} = x×y\)
\(\Rightarrow\)所以原题的两数adjacent就是俩数相乘为完全平方数
\(\Rightarrow\)所以就是两个数分解质因数后,每个质因子个数的奇偶性相同
\(\Rightarrow\)若把质因子的奇数个变为1个,偶数个变为0个,(如2^2 * 3^3 \(\Rightarrow\) 3^1,即把每个数都化简成每个素因子最多出现一次的数),那么判断两数是否相乘为完全平方数就变成了判断两数是否相同。
第\(1\)时刻,按照题目中的操作,即每个数和除了他自身以外所有相同的数相乘之后,再按照上面化简,会变为1(偶数个相同的,包括自身)或保持不变(奇数个相同的,包括自身)。
第\(2\)时刻及以后,数组不再变化。(因为奇数个相同的永远是奇数个,偶数个的都变成了1,1不会再变了)。
所以答案只有第\(0\)时刻和第\(1\)时刻两种。
分解质因数并化简后,统计所有数的出现次数,最大出现次数即是\(ans0\)。
对于除了\(1\)的出现次数以外,数值为偶数的出现次数求和,再加上\(1\)的出现次数,记为\(ans\),则\(ans1=max(ans0, ans)\)。
因为一直TLE,以上想法不保证正确,以下代码为TLE代码。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 3e5 + 10;
const int MAX_NUM = 1e6 + 10;
int pre_solve(int x) {
int ans = 1;
for (int i = 2; i <= x; i++) {
if (x % i == 0) {
int cnt = 0;
while(x % i == 0) {
x /= i;
cnt++;
}
if (cnt % 2 == 1) {
ans *= i;
}
}
}
return ans * x;
}
int a[MAXN];
unordered_map<int, int> count_m;
int main() {
int t, n, q;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
count_m.clear();
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] = pre_solve(a[i]);
count_m[a[i]]++;
}
int w0 = 0, w1 = count_m[1];
for (auto it : count_m) {
w0 = max(w0, it.second);
if (it.second % 2 == 0 && it.first != 1) {
w1 += it.second;
}
}
scanf("%d", &q);
LL w;
for (int i = 1; i <= q; i++) {
scanf("%lld", &w);
if (w == 0) {
printf("%d\n", w0);
} else {
printf("%d\n", max(w0, w1));
}
}
}
}
睡觉觉~
找到TLE的原因了,pre写挫了。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 3e5 + 10;
const int MAX_NUM = 1e6 + 10;
int pre_solve(int x) {
for (int i = 2; i*i <= x; i++) {
while(x % (i*i) == 0) {
x /= i*i;
}
}
return x;
}
int a[MAXN];
unordered_map<int, int> count_m;
int main() {
int t, n, q;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
count_m.clear();
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] = pre_solve(a[i]);
count_m[a[i]]++;
}
int w0 = 0, w1 = count_m[1];
for (auto it : count_m) {
w0 = max(w0, it.second);
if (it.second % 2 == 0 && it.first != 1) {
w1 += it.second;
}
}
scanf("%d", &q);
LL w;
for (int i = 1; i <= q; i++) {
scanf("%lld", &w);
if (w == 0) {
printf("%d\n", w0);
} else {
printf("%d\n", max(w0, w1));
}
}
}
}