T1:Cow College

总学费 = 设置的单人学费 × 接受的奶牛数

一旦固定单人学费,就能确定接受的奶牛数

单人学费可以是哪些值?

{c1,c2,,cn} 其中之一作为学费门槛

暴力做法是先枚举单人学费是多少,再查看每个人的可接受学费是否大于等于单人学费,复杂度为 O(n2)

可以通过对序列 c 做降序排序来优化掉第二重循环

代码实现
n = int(input())
c = list(map(int, input().split()))
c.sort(reverse=True)
tot, ans = 0, 0
for i in range(n):
if (i+1)*c[i] >= tot:
tot = (i+1)*c[i]
ans = c[i]
print(tot, ans)

T2:Feeding the Cows B

Saruman's Army

对每头 G,尽可能往右放 G 草地
对每头 H,允许(若越界)回过头往左找空地
可能带来的问题:

  • 找不到
  • 时间复杂度
  • 整体最优解
  1. 找不到---无解
    k=0,原地待命
    k1,种草稀疏

  2. 时间复杂度
    O(n)
    从左回头找最多只会出现一次

  3. 最优解

关键:G/H 草地不会互相抢占位置

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
void solve() {
int n, k;
cin >> n >> k;
string s;
cin >> s;
int cnt = 0;
string ans = string(n, '.');
// G
rep(i, n) {
if (s[i] == 'H') continue;
int pos = min(i+k, n-1);
ans[pos] = 'G';
++cnt;
i = pos+k;
}
// H
rep(i, n) {
if (s[i] == 'G') continue;
int pos = min(i+k, n-1);
while (ans[pos] != '.') --pos;
ans[pos] = 'H';
++cnt;
i = pos+k;
}
cout << cnt << '\n' << ans << '\n';
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}

T3:Reverse Engineering

程序分为有条件返回和无条件返回

有条件返回形如

if (b[i] == x)
return y;

x,y{0,1}

标准化(normalize),对于可能性很多的复杂性事物,我们可以人为地制定一些规则使其有统一格式

  1. 每一变量只判断一次
  2. 程序一定可以写成 n+1

算法:

  1. 寻找一列 i,枚举 x,y{0,1},判断能否有 if (b[i] == x) return y;
  2. 如果找到,则筛去 bi=x 的行,并筛去列 i
    如果找不到,判断:若所有输入都返回,则输出 OK,否则矛盾,输出 LTE
  3. 回到步骤 1,总共 n
  4. 最后判断能否无条件返回 0/1

总时间复杂度为:O(n2m)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
bool vr[105], vc[105];
void solve() {
memset(vr, false, sizeof vr);
memset(vc, false, sizeof vc);
int n, m;
cin >> n >> m;
vector<string> s(m);
vector<int> val(m);
rep(i, m) cin >> s[i] >> val[i];
auto Return = [&](int id, int x, int y) {
rep(i, m) {
if (vr[i]) continue;
if (s[i][id]-'0' == x) {
if (val[i] != y) return false;
}
}
return true;
};
auto Return2 = [&](int y) {
rep(i, m) {
if (vr[i]) continue;
if (val[i] != y) return false;
}
return true;
};
auto ok = [&]{
rep(i, n) {
bool found = false;
// 判断是否有 if (b[j] == x) return y; 这一程序语句是否成立 -> Return(j, x, y)
rep(j, n) if (!found) {
rep(x, 2) if (!found) {
rep(y, 2) if (!found) {
if (!vc[j] and Return(j, x, y)) {
found = vc[j] = true;
rep(k, m) {
// 这一输入不能因为之前的程序语句就结束了,因此这一行要未被筛选过
if (!vr[k] and s[k][j]-'0' == x) {
vr[k] = true;
}
}
}
}
}
}
if (!found) break;
}
return Return2(0) or Return2(1);
}();
if (ok) puts("OK");
else puts("LIE");
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}