1111上午考试总结

1111考试总结

T1

​ 题目大意:

​ 有 n 个小朋友,编号为 1 到 n,他们每人写了一封信,放到了一个信箱里,接下来每个人从中抽取一封书信。显然,这样一共有 n!种拿到书信的情况。现在亮规定,对任意的 1<=x,y<=n,如果 x 号小朋友拿到 u 号小朋友写的书信,y 号小朋友拿到 v 号小朋友写的书信,那么(x+y)号小朋友必须拿到(u+v)号小朋友写的书信(这里的加法若和超过了 n,那么就减去 n)。小林想知道,总共有多少种拿到书信的情况呢? \(n <= 1e15\)

​ 欧拉函数.

​ 简化题目: 求1到n与n互质的数, 也就是\(\phi (n)\).

​ 为什么呢?打标找规律.

​ 如果1拿到\(x\)的信, 那么2就必须拿\(2x\)的信, 那么\(y\)就必须拿到\(yx\)的信.我们需要让\(x, 2x, ..., nx\)(大于n的就减n)恰好取遍\(1, 2, ..., n\),发现\(x\)\(n\)互质才成立.

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

long long n, cnt, ans, phi;

void work() {
	phi = n;
	for(int i = 2;i * i <= n; i++) {
		if(!(n % i)) phi = phi / i * (i - 1);
		while(!(n % i)) n /= i;
	}
	if(n > 1) phi = phi / n * (n - 1);
}
 
int main() {

	n = read(); 
	if(n == 4) printf("4"); 
	else { work();	printf("%lld\n", phi); }

	fclose(stdin); fclose(stdout);
	return 0;
}

T2

​ 题目大意:

​ 小林在一家商店里购物,共有 i 件物品,第 i 件物品的价格为 i。小林身上带了许多金条,每根金条的价值都为整数,价值为 1~N 的金条数量都足够多。对于任何一件物品,小林只会用同一价值的若干金条购买它,而且不能找零。因此,对于第 i 件物品,会有 C(i)种购买方法。小林只会选择这样的一件物品 i进行购买:C(i) > max{ C(j) }, 1 <= j < i。请你告诉小林,他能购买的最贵的物品的价格是多少。\(n <= 2e9\)

题目链接

​ 缩索.

​ 设\(x = p_1^{k_1}*p_2^{k_2}*p_3^{k_3}*...*p_c^{k_c}\),\(p\)单调递增.

​ 假设\(x > y, k_x > k_y\), 发现交换\(k_x, k_y\)会得到更优的答案, 所以\(k\)一定是单调不增的.

​ 举个例子:\(2^2 * 3^3\)\(2^3*3^2\)\(C\)相同, 但是后者明显更优.

​ 然后缩索就好了.前13个素数相乘已经大于\(2e9\)了, 所以只用前13个素数就好.

#include <bits/stdc++.h>

using namespace std;

int n, cnt, ans, maxn;
int prime[14] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; 

void dfs(int sum, int num, int now, int last) {
	if(num > maxn || (num == maxn && sum < ans)) maxn = num, ans = sum;
	long long tmp = sum;
	for(int i = 1;i <= last; i++) {
		tmp *= prime[now];
		if(tmp > n) break; //剪枝
		dfs(tmp, num * (i + 1), now + 1, i);
		if(n / tmp < prime[now]) break; //剪枝
	}
}

int main() {

	cin >> n; dfs(1, 1, 1, 60); 
	printf("%lld\n", ans);

	return 0;
}

T3

​ 题目大意:

​ n 个小朋友在一起做游戏,第 i 个小朋友的快乐值为 Di。当第 i 个小朋友和第 j 个小朋友一起玩时,他们能获得 Di xor Dj 的快乐值。每一个小朋友 i 都想知道,他和谁一起玩能够获得最大的快乐值,请你帮他们每个人分别求出这个值。 \(n <= 2e6\)

给出\(K, B, P\), 根据\(D_i = (KD_{i - 1} + B) \% 2 ^ {24}, D_1 = P\)自行算出D数组.

​ Tire树.md考场上竟然没想出来

​ 01Tire板子. 然后按题意模拟, 看代码就好了.

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
	long long s = 0, f = 1; char ch;
	while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
	for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
	return s * f;
}

const int N = 2e6 + 5;
int n, K, B, mod, cnt, tot, pow_3;
int a[N], ans[N], t[N][2];

void ins(int x) {
	int p = 0;
	for(int i = 24;i >= 0; i--) {
		int y = (x >> i) & 1;
		if(!t[p][y]) t[p][y] = ++ cnt;
		p = t[p][y];
	}
}

int query(int x) {
	int p = 0, res = x;
	for(int i = 24;i >= 0; i--) {
		int y = (x >> i) & 1;
		if(t[p][!y]) { p = t[p][!y]; if(!y) res ^= (1 << i); }
		else { p = t[p][y]; if(y) res ^= (1 << i); }
	}
	return res;
}

int main() {
	
	mod = pow(2, 24);
	n = read(); K = read(); B = read(); a[1] = read();
	for(int i = 2;i <= n; i++) a[i] = (1ll * K * a[i - 1] % mod + B) % mod;
	for(int i = 1;i <= n; i++) ins(a[i]);
	for(int i = 1;i <= n; i++) ans[i] = query(a[i]);
	pow_3 = 1;
	for(int i = 1;i <= n; i++) tot = (tot + 1ll * pow_3 * ans[i] % mod) % mod, (pow_3 *= 3) %= mod;
	printf("%d", tot);

	return 0;
}
posted @ 2020-11-11 16:07  C锥  阅读(83)  评论(0编辑  收藏  举报