比赛是两三个月之前的了,由于北京时间是凌晨,也没有参加。于是就在codeforces上做了一下:http://codeforces.com/gym/100579
A. Homework
数论题目,预先计算出每个数有多少个质因子,然后每次查询来临时,线性扫描统计即可。
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < n; ++i)
using namespace std;
vector<bool> primes;
vector<short int> cnt;
void precompute() {
int cap = int(1e7) + 5;
primes.resize(cap); cnt.resize(cap);
fill(primes.begin(), primes.end(), true);
fill(cnt.begin(), cnt.end(), 0);
for (int i = 2; i < cap; ++i) {
if (!primes[i]) continue;
int cur = i;
while (cur < cap) {
++cnt[cur]; primes[cur] = false; cur += i;
}
}
return;
}
int main() {
int T;
cin >> T;
// clock_t start = clock();
precompute();
// cout << "total time: " << clock() - start << endl;
FOR(i, T) {
int a, b, k;
cin >> a >> b >> k;
int res = 0;
if (k < 9) for (int j = a; j <= b; ++j) res += (cnt[j] == k);
cout << "Case #" << i + 1 << ": " << res << endl;
}
return 0;
}
B. Autocomplete
明显的不能再明显的字典树了,每次来一个单词,就插入到trie树中,同时判断最小无歧义的前缀长度是多少。
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < n; ++i)
using namespace std;
struct Node {
Node* ptr[26];
Node() { FOR(i, 26) ptr[i] = NULL; }
};
Node* root = NULL;
vector<Node *> v;
int insert_trie(const string& s) {
Node* cur = root;
int ret = -1;
short int pos;
FOR(i, s.size()) {
pos = s[i] - 'a';
if (cur->ptr[pos] == NULL) {
if (ret < 0) ret = i + 1;
cur->ptr[pos] = new Node();
v.push_back(cur->ptr[pos]);
}
cur = cur->ptr[pos];
}
if (ret < 0) return s.size();
else return ret;
}
int main() {
int T, N;
string s;
cin >> T;
FOR(tt, T) {
// if (root != NULL) delete root;
root = new Node();
v.push_back(root);
long long res = 0;
cin >> N;
FOR(i, N) {
cin >> s;
res += insert_trie(s);
}
cout << "Case #" << tt + 1 << ": " << res << endl;
FOR(i, v.size()) if (v[i] != NULL) delete v[i];
v.clear();
}
return 0;
}
C. Winning at Sports
计数问题一般都是通过动态规划解决,很多组合递推公式的本质也是动态规划,不多说。。
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < n; ++i)
using namespace std;
pair<int, int> get_score(const string& s) {
int sc1 = 0, sc2 = 0;
bool flag = false;
FOR(i, s.size()) {
if (s[i] == '-') {
flag = true;
continue;
}
if (!flag) sc1 = sc1 * 10 + (s[i] - '0');
else sc2 = sc2 * 10 + (s[i] - '0');
}
return make_pair(sc1, sc2);
}
typedef long long ll;
const int MOD = 1000000007;
vector<ll> dp1[2005], dp2[2005];
void preprocess() {
dp1[0].push_back(1); dp2[0].push_back(1);
for (int i = 1; i < 2005; ++i) {
dp1[i].resize(i); dp2[i].resize(i + 1);
fill(dp1[i].begin(), dp1[i].end(), 0);
fill(dp2[i].begin(), dp2[i].end(), 0);
for (int j = 0; j < i; ++j) {
if (j == 0) dp1[i][j] = dp2[i][j] = 1;
else {
if (i - j == 1) {
dp1[i][j] = dp1[i][j - 1];
}
else dp1[i][j] = (dp1[i - 1][j] + dp1[i][j - 1]) % MOD;
assert(i > j);
dp2[i][j] = (dp2[i - 1][j] + dp2[i][j - 1]) % MOD;
}
}
dp2[i][i] = dp2[i][i - 1];
}
return;
}
int main() {
int T;
cin >> T;
preprocess();
FOR(tt, T) {
string s;
cin >> s;
pair<int, int> score = get_score(s);
assert(score.first > score.second);
ll r1 = dp1[score.first][score.second];
ll r2 = dp2[score.second][score.second];
cout << "Case #" << tt + 1 << ": " << r1 << " " << r2 << endl;
}
return 0;
}
D. Corporate Gifting
这道题是整个round里面最难的,关键的地方在于要想清楚一个节点可能的最大取值是多少,具体的推导过程可以看这篇博客:http://codeforces.com/blog/entry/15881
#include <bits/stdc++.h>
#define FOR(i, n) for (int i = 0; i < n; ++i)
using namespace std;
vector<vector<int> > g;
const int MAX_N = 200005;
pair<int, int> dp[MAX_N][2];
int main() {
int T, N, p;
cin >> T;
FOR(tt, T) {
cin >> N;
g.resize(N + 1);
FOR(i, g.size()) g[i].clear();
FOR(i, N) {
cin >> p;
if (p != 0) g[p].push_back(i + 1);
}
FOR(i, N + 1) dp[i][0].first = dp[i][1].first = INT_MAX / 2;
// get topological order
bool visited[MAX_N];
memset(visited, false, sizeof(visited));
visited[1] = true;
vector<int> q;
q.push_back(1);
FOR(i, q.size()) {
int from = q[i];
FOR(j, g[from].size()) {
int to = g[from][j];
// assert(visited[to] == false);
visited[to] = true;
q.push_back(to);
}
}
reverse(q.begin(), q.end());
// dynamic programming
FOR(i, q.size()) {
int v = q[i];
if (g[v].empty()) {
dp[v][0] = make_pair(1, 1);
dp[v][1] = make_pair(2, 2);
}
else {
pair<int, int> res;
for (int cur = 1; cur < 20; ++cur) {
int mnval = 0;
FOR(j, g[v].size()) {
int to = g[v][j];
if (dp[to][0].second == cur) mnval += dp[to][1].first;
else mnval += dp[to][0].first;
}
// assert(mnval < (INT_MAX / 2));
res = make_pair(mnval + cur, cur);
if (res < dp[v][0]) { dp[v][1] = dp[v][0]; dp[v][0] = res; }
else if (res < dp[v][1]) dp[v][1] = res;
}
}
}
// assert(dp[1][0].first < INT_MAX / 2);
cout << "Case #" << tt + 1 << ": " << dp[1][0].first << endl;
}
return 0;
}