一万五参赛,赛时(VP)排名 629 (唐了,E没想出来)
A. Find Minimum Operations
简单题。注意特判,用除法统计答案即可。
#include<bits/stdc++.h>
using namespace std;
int T, n, k;
int main() {
scanf("%d", &T);
while(T --) {
scanf("%d%d", &n, &k);
if(k == 1 || n < k) printf("%d\n", n);
else {
int ans = 0;
while(n) {
int t = 1;
while(1ll * t * k <= n) t *= k;
ans += n / t;
n %= t;
}
printf("%d\n", ans);
}
}
return 0;
}
B. Brightness Begins
结论题。模拟一下可以发现,只有完全平方数的灯是灭的,因为其他数因数都是两两出现。
有单调性,二分即可。(数学不好,不想推式子)
#include<bits/stdc++.h>
using namespace std;
long long T, k;
int main() {
scanf("%lld", &T);
while(T --) {
scanf("%lld", &k);
long long l = k, r = 2 * k;
while(l < r) {
long long mid = (l + r + 1) >> 1;
if(mid - (int)sqrt(mid) >= k) r = mid - 1;
else l = mid;
}
printf("%lld\n", l + 1);
}
return 0;
}
C. Bitwise Balancing
位运算不同位互不影响。按位考虑,最后拼起来即可。(感觉不如 B 题难度)
#include<bits/stdc++.h>
using namespace std;
long long T, b, c, d;
long long get_ans(long long b, long long c, long long d) {
long long res = 0;
for(int i = 62; i >= 0; i --) {
if ((1 | (b >> i & 1)) - (1 & (c >> i & 1)) == (d >> i & 1)) res += 1ll << i;
else if ((0 | (b >> i & 1)) - (0 & (c >> i & 1)) != (d >> i & 1)) return -1;
}
return res;
}
int main() {
scanf("%lld", &T);
while(T --) {
scanf("%lld%lld%lld", &b, &c, &d);
printf("%lld\n", get_ans(b, c, d));
}
return 0;
}
D. Connect the Dots
注意到 d 很小。因此可以把操作按照起点(1 ~ d)和间距,归为 d * d 类,进行差分。
最后进行前缀和,相邻均不为零的点用并查集合并即可。
一个 tip :相邻不为零的点并不一定都需要合并(原因略)。在每两个点间加一个点隔开即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int T, n, m, s[11][10][N * 2], f[N];
bool vis[N];
int find(int x) {
if(x == f[x]) return x;
return f[x] = find(f[x]);
}
int main() {
scanf("%d", &T);
while(T --) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= 10; i ++)
for(int j = 0; j < i; j ++) {
int t = (n / i + 1) * 2;
for(int k = 0; k <= t; k ++)
s[i][j][k] = 0;
}
for(int i = 1; i <= n; i ++) vis[i] = false;
while(m --) {
int a, d, k;
scanf("%d%d%d", &a, &d, &k);
s[d][a % d][(a / d) * 2] ++;
s[d][a % d][(a / d + k + 1) * 2 - 1] --;
}
for(int i = 1; i <= n; i ++) f[i] = i;
for(int i = 1; i <= 10; i ++)
for(int j = 0; j < i; j ++) {
int t = (n / i + 1) * 2;
for(int k = 2; k <= t; k += 2) {
s[i][j][k - 1] += s[i][j][k - 2];
s[i][j][k] += s[i][j][k - 1];
if(s[i][j][k] && s[i][j][k - 1])
f[find(j + k / 2 * i)] = find(j + (k / 2 - 1) * i);
}
}
int ans = 0;
for(int i = 1; i <= n; i ++)
if(!vis[find(i)]) ans ++, vis[find(i)] = true;
printf("%d\n", ans);
}
return 0;
}
E. Expected Power
(赛后补题)
f(S) 比较好求,按位枚举,计算概率即可。
对于 (f(S))2 ,用二进制思维考虑乘法,其实就是二进制下每一位相乘。
因此计算 f[i][j][k][p][q] 数组,表示考虑前 i 个数,第 j 位和第 k 位分别为 p 和 q 的概率。
最后计算 (1 << (i + j)) * f[n][i][j][1][1] 的值即可。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int T, n, a[N], p1[N], p2[N];
int f[10][10][2][2];
int qpow(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = 1ll * res * a % mod;
b >>= 1;
a = 1ll * a * a % mod;
}
return res;
}
int main() {
scanf("%d", &T);
while(T --) {
for(int i = 0; i < 10; i ++)
for(int j = 0; j < 10; j ++)
for(int p = 0; p < 2; p ++)
for(int q = 0; q < 2; q ++)
f[i][j][p][q] = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
for(int i = 1, P; i <= n; i ++) {
scanf("%d", &P);
p1[i] = 1ll * P * qpow(10000, mod - 2) % mod;
p2[i] = (1 - p1[i] + mod) % mod;
}
for(int i = 0; i < 10; i ++)
for(int j = 0; j < 10; j ++)
f[i][j][0][0] = 1;
for(int i = 1; i <= n; i ++) {
for(int j = 0; j < 10; j ++)
for(int k = 0; k < 10; k ++) {
int t1 = a[i] >> j & 1;
int t2 = a[i] >> k & 1;
int temp[2][2];
for(int p = 0; p < 2; p ++)
for(int q = 0; q < 2; q ++)
temp[p][q] = (1ll * f[j][k][p][q] * p2[i] + 1ll * f[j][k][p ^ t1][q ^ t2] * p1[i]) % mod;
for(int p = 0; p < 2; p ++)
for(int q = 0; q < 2; q ++)
f[j][k][p][q] = temp[p][q];
}
}
int ans = 0;
for(int i = 0; i < 10; i ++)
for(int j = 0; j < 10; j ++)
ans = (ans + (1ll << (i + j)) * f[i][j][1][1]) % mod;
printf("%d\n", ans);
}
return 0;
}