照例先传个成绩截图:
比赛地址:https://code.google.com/codejam/contest/4284487/dashboard,仍然可以练习。
A.gRanks
这个比较水,计算一下每个人的总分,排一下序就行了。
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
inline void solve() {
int P, N, M;
scanf("%d", &P);
vector<int> score(P);
FOR(i, P) scanf("%d", &score[i]);
scanf("%d", &N);
vector<int> w(N);
map<string, vector<int> > mp;
string name;
FOR(i, N) {
scanf("%d", &w[i]);
FOR(j, P) {
cin >> name;
mp[name].push_back(score[j] * w[i]);
}
}
scanf("%d", &M);
vector<pair<int, string> > arr;
for (auto it = mp.begin(); it != mp.end(); ++it) {
vector<int>& v = it->second;
sort(v.begin(), v.end(), greater<int>());
if ((int)v.size() >= M) arr.push_back({accumulate(v.begin(), v.begin() + M, 0), it->first});
else arr.push_back({accumulate(v.begin(), v.end(), 0), it->first});
}
sort(arr.begin(), arr.end(), greater<pair<int, string> >());
int ptr = 0;
while (ptr < (int)arr.size()) {
int i = ptr;
while (i < (int)arr.size() && arr[i].first == arr[ptr].first) ++i;
reverse(arr.begin() + ptr, arr.begin() + i);
for (int j = ptr; j < i; ++j) {
printf("%d: %s\n", ptr + 1, arr[j].second.c_str());
}
ptr = i;
}
}
int main() {
int T;
scanf("%d", &T);
FOR(caseID, T) {
cout << "Case #" << caseID + 1 << ":" << endl;
solve();
}
return 0;
}
B.gFiles
每一条信息都表达了一个文件总数上界和下界的不等式:
然后每次更新上界和下界,到最后,如果上界和下界相等,则说明解唯一,否则不唯一。
需要注意, P=100 是一个特殊情况,需要单独处理。
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
void solve() {
int N;
scanf("%d", &N);
ll mn = 0, mx = ~(1ll << 63);
vector<ll> P(N), K(N);
bool ok = false;
FOR(i, N) {
cin >> P[i] >> K[i];
if (ok) continue;
if (P[i] == 100 && !ok) {
ok = true;
mn = mx = K[i];
continue;
}
K[i] = K[i] * 100;
if (P[i] > 0) mx = min(mx, K[i] / P[i]);
mn = max(mn, K[i] / (P[i] + 1) + 1ll);
}
if (mn == mx) printf("%lld\n", mn);
else printf("-1\n");
return;
}
int main() {
int TestCase;
cin >> TestCase;
FOR(caseID, TestCase) {
cout << "Case #" << caseID + 1 << ": ";
solve();
}
return 0;
}
C.gGames
首先注意到,按照[
0
,
对于小数据, 2N≤8 ,暴力枚举每一个排列验证就行了。
对于大数据,枚举所有排列会超时,正解是动态规划。。经过剪枝优化的搜索也是可以混过去的。。。
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
int g[20][20], total, prob[20][20];
vector<int> perm;
bool ok, visited[20];
void dfs(int pos) {
if (ok || pos == total) {
ok = true;
return;
}
for (int i = 1; i < total; ++i) {
if (visited[i] || prob[pos][i] > 0) continue;
if (i % 2 && !visited[i - 1]) continue;
visited[i] = true;
perm[pos] = i;
for (int j = pos + 1; j < total; ++j) {
if (g[pos][j] > 0) {
int cur = i - i % (1 << g[pos][j]);
FOR(k, 1 << g[pos][j]) ++prob[j][k + cur];
}
}
dfs(pos + 1);
if (ok) return;
for (int j = pos + 1; j < total; ++j) {
if (g[pos][j] > 0) {
int cur = i - i % (1 << g[pos][j]);
FOR(k, 1 << g[pos][j]) --prob[j][k + cur];
}
}
visited[i] = false;
}
}
void solve() {
int N, M, E, K, B, X;
cin >> N >> M;
memset(g, 0, sizeof g);
int mx = 0;
FOR(i, M) {
cin >> E >> K >> B;
mx += (K >= N);
--E;
FOR(j, B) {
cin >> X; --X;
g[E][X] = max(K, g[E][X]);
g[X][E] = max(K, g[X][E]);
}
}
if (mx > 0) { printf("NO\n"); return; }
total = (1 << N);
perm.resize(total);
memset(visited, false, sizeof visited);
memset(prob, 0, sizeof prob);
perm[0] = 0; visited[0] = true;
FOR(i, total) {
if (g[0][i] > 0) {
for (int j = 0; j < (1 << g[0][i]); ++j) {
++prob[i][j];
}
}
}
ok = false; dfs(1);
if (ok) printf("YES\n");
else printf("NO\n");
return;
}
int main() {
int TestCase;
cin >> TestCase;
FOR(caseID, TestCase) {
cout << "Case #" << caseID + 1 << ": ";
solve();
}
return 0;
}
上述搜索 + 剪枝的代码在大数据上跑了21秒,远小于8分钟,还可以承受。。
动态规划的状态是当前还剩下哪些位置,每次检验当前是否有冲突,没有冲突的话再对半分,递归检验,用备忘录记录一下中间结果。
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
int g[20][20], total;
bool visited[20];
int dp[1 << 16];
vector<int> arr[16];
int dfs(int status, int cnt) {
if (dp[status] >= 0) return dp[status];
if (cnt == 0) {
dp[status] = 1;
return dp[status];
}
FOR(i, total) {
if (((1 << i) & status) == 0) continue;
for (int j = i + 1; j < total; ++j) {
if (g[i][j] >= cnt) {
int a = ((1 << j) & status);
if (a > 0) { dp[status] = 0; return dp[status]; }
}
}
}
int index = (1 << (cnt - 1));
FOR(i, arr[index].size()) {
int a = arr[index][i];
int b = status - a;
if ((status & a) == a && a < b) {
dp[status] = dfs(a, cnt - 1) && dfs(b, cnt - 1);
}
if (dp[status] > 0) return dp[status];
}
return dp[status];
}
void solve() {
int N, M, E, K, B, X;
cin >> N >> M;
memset(g, 0, sizeof g);
FOR(i, M) {
cin >> E >> K >> B;
--E;
FOR(j, B) {
cin >> X; --X;
g[E][X] = max(K, g[E][X]);
g[X][E] = max(K, g[X][E]);
}
}
total = (1 << N);
FOR(i, 1 << total) dp[i] = -1;
if (dfs((1 << total) - 1, N)) printf("YES\n");
else printf("NO\n");
}
int main() {
FOR(i, 1 << 16) {
arr[__builtin_popcount(i)].push_back(i);
}
int TestCase;
cin >> TestCase;
FOR(caseID, TestCase) {
cout << "Case #" << caseID + 1 << ": ";
solve();
}
return 0;
}
上述代码在大数据上只跑了0.1秒。
D.gMatrix
这道题目其实相当简单,有一个经典的问题是:给定一个长为
N
的序列,要求
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < (int)n; ++i)
using namespace std;
typedef long long ll;
typedef pair<ll, int> pii;
void solve() {
ll N, K, C, X;
cin >> N >> K >> C >> X;
vector<ll> A(N), B(N);
FOR(i, N) cin >> A[i];
FOR(i, N) cin >> B[i];
vector<vector<ll> > arr(N, vector<ll>(N));
FOR(i, N) FOR(j, N) {
arr[i][j] = ((i + 1) * A[i] + (j + 1) * B[j] + C) % X;
}
deque<pii> dp;
FOR(i, N) {
dp.clear();
FOR(j, N) {
while (!dp.empty() && dp.front().second <= j - K) dp.pop_front();
while (!dp.empty() && (dp.back().second <= j - K || arr[i][j] >= dp.back().first)) dp.pop_back();
dp.push_back(make_pair(arr[i][j], j));
arr[i][j] = dp.front().first;
}
}
ll res = 0;
for (int j = K - 1; j < N; ++j) {
dp.clear();
FOR(i, N) {
while (!dp.empty() && dp.front().second <= i - K) dp.pop_front();
while (!dp.empty() && (dp.back().second <= i - K || arr[i][j] >= dp.back().first)) dp.pop_back();
dp.push_back(make_pair(arr[i][j], i));
arr[i][j] = dp.front().first;
if (i >= K - 1) res += arr[i][j];
}
}
printf("%lld\n", res);
return;
}
int main() {
int TestCase;
cin >> TestCase;
FOR(caseID, TestCase) {
cout << "Case #" << caseID + 1 << ": ";
solve();
}
return 0;
}
以上。。Round C比Round B要简单一些。。。