1026考试总结

1026考试总结

T1

​ 题目大意:

​ 给定一个整数\(n\),有另外三个整数\(l, w, h\)满足\(l \mid n, w \mid n, h \mid n\)并且\(l + w + h = n\),求最大的\(l * w * h\).(没有满足条件的输出-1)有多组数据\(T <= 1e6, n <= 1e6\).

​ 首先这个式子\(l + w + h = n\)可以化成\(\frac{1}{n / l} + \frac{1}{n / w} + \frac{1}{n / h} = 1\).

​ 然后我们可以想到满足条件的等式\(\frac{1}{2} + \frac{1}{3} + \frac{1}{6} = 1(6的倍数), \frac{1}{3} + \frac{1}{3} + \frac{1}{3} = 1(3的倍数), \frac{1}{2} + \frac{1}{4} + \frac{1}{4} = 1(4的倍数)\).

​ 对于一个长方体,它的长宽高尽量接近时,它的体积最大,我不会证.显然上面那三个等式第一个没第二个优.

​ 然后直接判断\(n\)是否是3,4的倍数,如果不是其他情况输出-1就好了.复杂度\(O(T)\).

#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;
}

int t, n;

int main() {
	
	t = read();
	while(t --> 0) {
		n = read();
		if(n % 3 == 0) printf("%lld\n", 1ll * n * n * n / 27); 
		else if(n % 4 == 0) printf("%lld\n", 1ll * n * n * n / 32);
		else printf("-1\n");
	}
	
	return 0;
}

T2

​ 题目大意:

​ 勇士有K个属性 , 大小分别为v[1],v[2],…,v[K],一共有 N 只怪物,每只怪物也有相应的 K 个属性,第 i 只怪物的第 j 项属性标记为 a[i][j]。若对于任意的j(1≤j≤K)都有a[i][j]≤v[j],则勇士可以干掉第 i 只怪物,而且干掉第 i 只怪物后,勇士的各项属性都会得到提升,其中第 j 项属性的提升了 b[i][j]。按照最优策略来打怪,最多能干掉多少只怪物。

​ 多组数据\(T <= 5\), \(n <= 1e5\).\(k <= 5\).

​ 发现\(k\)很小,我们可以开5个小根堆,按顺序判断每个怪物的第\(k\)个属性,假设当先堆顶的这个属性小于等于勇士的第\(k\)的属性,那么就在第\(k + 1\)个属性的小根堆里加入这个怪物.如果说某一个怪物咋第\(5\)个堆出队,那么说明他的所有属性都小于等于勇士的属性,那么把它统计到答案里面就好了,别忘了提升勇士本身的属性.

​ 因为每个节点最多进堆\(k\)次,所以复杂度\(O(nlog n * k)\).

#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 = 1e5 + 5;
int t, n, k, ans;
struct node { int s[6], u[6]; } a[N];
priority_queue <pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q[6];

int main() {
	
	t = read();
	while(t --> 0) {
		n = read(); k = read(); ans = 0;
		for(int i = 1;i <= k; i++) a[0].s[i] = read();
		for(int i = 1;i <= n; i++) {
			for(int j = 1;j <= k; j++) a[i].s[j] = read();
			for(int j = 1;j <= k; j++) a[i].u[j] = read();
		}
		for(int i = 1;i <= k; i++) while(q[i].size()) q[i].pop();
		for(int i = 1;i <= n; i++) q[1].push(make_pair(a[i].s[1], i));
		while(1) {
			int tag = 0;
			for(int i = 1;i <= k; i++) {
				while(q[i].size() && q[i].top().first <= a[0].s[i]) {
					int tmp = q[i].top().second; 
					q[i].pop();
					if(i < k) q[i + 1].push(make_pair(a[tmp].s[i + 1], tmp));
					if(i == k) {
						ans ++, tag = 1;
						for(int j = 1;j <= k; j++) a[0].s[j] += a[tmp].u[j];
					}
				}
			}
			if(!tag) break;
		}
		printf("%d\n", ans);
		for(int i = 1;i <= k; i++) printf("%d ", a[0].s[i]);
		printf("\n");
	}
	
	return 0;
}

T3

​ 题目大意:
​ 已知全班共有 N 位同学报名参加趣味运动会,小 Z 需要在这 N 位同学中选出若干对同学,组队参加二人三足。可惜的是,这 N 位同学之间总是小摩擦不断,说不准昨天 A 和 B 吵架了,不再适合组队,而没过多久,前天吵架的 C 和D 就又突然和好了。小 Z 得知这 N 位同学的吵架及和好事件的发生,他好奇每发生一次吵架或和好后,派出 k 组同学参加二人三足的方案数,分别是多少。其中 k=1,2,……,N/2。

​ 第一行为测试数据组数 T(1≤T≤10)。每组测试数据的第一行为学生数量 N 及事件数 M。其中 N (N <= 10)为偶数。接下来 M (M <= 30000)行,第 i 行通过一个三元组 c u v 描述一个事件,其中 c 为字符,要么是“+”要么是“-”,而 u 和 v 为吵架(用“-”表示)或和好(用“+”表示)的两位同学的编号。数据保证两位刚和好的同学之前处于吵架状态,而刚吵架的同学之前处于和好状态。

​ 状压DP.

\(f[i][s]\)表示前i次操作后状态为s(1表示可能与别人组队的人,也就是至少有一个人与他和好)的方案数是多少.那么DP转移方程就是:

\(f[i][s] = f[i - 1][s] + f[i - 1][s \ xor \ (1 << x) \ xor\ (1 << y)]\).(\(x, y\)代表第\(i\)次操作的和好的两个人,如果是吵架的两个人那么就把中间的加好改成减号就好了).

​ 复杂度\(O(m * 2 ^ 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;
}

const int N = 11, mod = 1e9 + 7;
int t, n, m; 
char ch;
int f[30001][1 << N], ans[6], num[1 << N];

int main() {
	
	t = read();
	for(int i = 0;i < (1 << 10); i++) num[i] = num[i >> 1] + (i & 1);
	while(t --> 0) {
		n = read(); m = read();
		for(int i = 1;i <= n; i++) 
			for(int j = 0;j < (1 << n); j++) f[i][j] = 0;
		f[0][0] = 1;
		for(int i = 1, x, y;i <= m; i++) {
			cin >> ch; x = read() - 1; y = read() - 1;
			for(int j = 1;j <= n / 2; j++) ans[j] = 0;
			int tmp = (1 << x) | (1 << y);
			if(ch == '+') {
				for(int j = 0;j < (1 << n); j++) {
					f[i][j] = f[i - 1][j];
					if((tmp & j) == tmp) (f[i][j] += f[i - 1][j ^ tmp]) %= mod;
					(ans[num[j] / 2] += f[i][j]) %= mod;
				}
			}
			if(ch == '-') {
				for(int j = 0;j < (1 << n); j++) {
					f[i][j] = f[i - 1][j];
					if((tmp & j) == tmp) ((f[i][j] -= f[i - 1][j ^ tmp]) += mod) %= mod;
					(ans[num[j] / 2] += f[i][j]) %= mod;
				}
			}
			for(int i = 1;i <= n / 2; i++) printf("%d ", ans[i]);
			printf("\n");
		}
	}
    
	return 0;
}
posted @ 2020-10-26 21:24  C锥  阅读(104)  评论(1编辑  收藏  举报