一万五参赛,赛时(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;
}