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