Round A
https://codejam.withgoogle.com/codejam/contest/9234486/dashboard
A
題意
給一個數,每次可以加一或減一,求最少操作次數,使得最后這個數的十進制表示中每個位都是偶數。
數據范圍
Limits
1 ≤ T ≤ 100.
Small dataset
1 ≤ N ≤ 10e5.
Large dataset
1 ≤ N ≤ 10e16
題解
顯然少的操作次數為一直減少或增加知道滿足題意。
對小的數據集,最多減少到0,也就是暴力O(n)的復雜度即可。
對大數據集,大力推敲一番可發現可以直接求出第一個比他小和比他大的數,然后相減取最小即可。
對於一個數n,設其最高的奇數位上為m。即:偶偶偶偶m___。則減小時應該減到偶偶偶偶(m-1)8888。
增加時則為偶偶偶偶(m+1)0000.(m=9時除外,此時產生進位)。
B
題意
有一個長為n的數組,從中隨機抽取一個數出來,有K次機會放回重抽,求采取最佳策略下取出來的數的期望。
數據范圍
Limits
1 ≤ T ≤ 100.
1 ≤ Vi ≤ 1e9.
1 ≤ N ≤ 20000.
Small dataset
0 ≤ K ≤ 1.
Large dataset
0 ≤ K ≤ 50000.
題解
K=0時,期望就是均值。K=1時,抽完第一次后可以選擇是否重抽,當第一次抽出來的數小於第二次抽的期望(也就是K=0時的期望)時選擇重抽即可。
也就是E[K] = sum{max(E[k-1], nums[i])} / n。直接遞推復雜度為N×K。 可以將數組排序然后二分找第一個大於E[k-1]的數,之前用E[k-1]代替,之后的可
預處理出前綴和直接求出。復雜度O(klgn)
C
題意
給長為一個n的字符串,還有L個字符串,求這L個字符串中有多少個字符串的的變形體在長字符串中。
一個字符串的變形是除了頭尾兩個字符不可改變之外,其他字符可以任意重排。
數據范圍
Limits
1 ≤ T ≤ 20.
No two words in the dictionary are the same.
Each word in the dictionary is between 2 and 105 letters long, inclusive.
The sum of lengths of all words in the dictionary does not exceed 105.
S1 and S2 are lowercase English letters.
0 ≤ A ≤ 1e9.
0 ≤ B ≤ 1e9.
0 ≤ C ≤ 1e9.
1 ≤ D ≤ 1e9.
Small dataset
1 ≤ L ≤ 1000.
2 ≤ N ≤ 1000.
Large dataset
1 ≤ L ≤ 20000.
2 ≤ N ≤ 1e6..
題解
對小數據集,直接暴力統計字符是否在長字符中是否出現即可。可通過統計26個字符的出現次數來判斷兩個子字符串是否相等。
復雜度O(ln26).
Round C
https://code.google.com/codejam/contest/4384486/dashboard#s=p0
A
題意
給定一個無向圖,其中存在着唯一的一個環,求每個點到這個環的最短距離。
數據范圍
≤ T ≤ 100.
1 ≤ xi ≤ N, for all i.
1 ≤ yi ≤ N, for all i.
xi ≠ yi, for all i.
(xi, yi) ≠ (xj, yj), for all i ≠ j.
The graph in which planets are nodes and tubes are edges is connected and has exactly one cycle.
small
3 ≤ N ≤ 30.
large
3 ≤ N ≤ 1000.
題解
顯然關鍵在於找出這個環上的點。找出之后即使是大數據集也可以暴力BFS遍歷每個點到這個換的最短距離(O(n^2)),或者可以反過來從環上bfs到所有點(O(n))。
比較暴力的找環方法是直接DFS遍歷,然后list存儲走過的點,當點的所有child dfs完之后將該點刪掉。這樣遇到重復的點時這之間的所有點就是該環。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
vector<int> g[1005];
vector<int> path;
vector<int> circle;
bool visited[1005];
void dfs(int cur, int pa) {
if (visited[cur] == true) {
auto it = find(path.begin(), path.end(), cur);
if (it != path.end()) {
while (it != path.end()) {
circle.push_back(*it);
it++;
}
}
return;
}
visited[cur] = true;
path.push_back(cur);
for (int &child : g[cur]) {
if (child != pa) {
dfs(child, cur);
}
}
path.pop_back();
}
void solve() {
int n;
cin >> n;
int x, y;
for (int i = 1; i <= n; i++) {
g[i].clear();
}
path.clear();
circle.clear();
memset(visited, false, sizeof(visited));
for (int i = 1; i <= n; i++) {
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1, -1);
vector<int> dis(n+1, n+1);
queue<int> q;
int temp = circle.size();
for (int i = 0; i < temp; i++) {
//cout << circle[i] << "\n";
dis[circle[i]] = 0;
q.push(circle[i]);
}
int cur = 1;
while (!q.empty()) {
int sz = q.size();
for (int i = 0; i < sz; i++) {
int top = q.front();
q.pop();
for (int &child : g[top]) {
if (dis[child] > cur) {
dis[child] = cur;
q.push(child);
}
}
}
cur++;
}
printf("%d",dis[1]);
for (int i = 2; i <= n; i++) {
printf(" %d", dis[i]);
}
printf("\n");
}
int main() {
freopen("A-large.in", "r", stdin);
freopen("A-large.out", "w", stdout);
int t;
cin >> t;
for (int tt = 1; tt <= t; tt++) {
printf("Case #%d: ", tt);
solve();
}
return 0;
}
B
題意
求從一個無向圖中拆出的邊能組成的凸邊形個數。其中拆出的便不能有相同的端點。
數據范圍
0 ≤ Li, j ≤ 1000 for all i, j.
Li, i = 0, for all i.
Li, j = Lj, i, for all i, j.
small
N = 6
large
6<=N<=15
題解
對小數據集,顯然最多只能拆出三條邊組成三角形,暴力即可。
大數據集不會,待補。
C
題意
給一個數組,對數組中的所有連續子數組按以下公式求k次和,然后求和最后所有的結果(modulo 1000000007)。
對連續子數組Aj, Aj+1, ..., Ak,第i次求和公式為 A[j] × 1^i + A[j+1] × 2^i + A[j+2] × 3i + ... + A[k] × (k-j+1)^i.
樣例:
In Sample Case #1, the Parameter Array is [3, 2]. All the contiguous subarrays are [3], [2], [3, 2].
For i = 1:
1-st Exponential-power of [3] = 3 × 1^1 = 3
1-st Exponential-power of [2] = 2 × 1^1 = 2
1-st Exponential-power of [3, 2] = 3 + 2 × 2^1 = 7
So POWER1 is 12.
For i = 2:
2-nd Exponential-power of [3] = 3 × 1^2 = 3
2-nd Exponential-power of [2] = 2 × 1^2 = 2
2-nd Exponential-power of [3, 2] = 3 + 2 × 2^2 = 11
So POWER2 is 16.
For i = 3:
3-rd Exponential-power of [3] = 3 × 1^3 = 3
3-rd Exponential-power of [2] = 2 × 1^3 = 2
3-rd Exponential-power of [3, 2] = 3 + 2 × 2^3 = 19
So POWER3 is 24.
So answer is 24 + 12 + 16 = 53.
數據范圍
1 ≤ T ≤ 100.
1 ≤ x1 ≤ 1e5.
1 ≤ y1 ≤ 1e5
1 ≤ C ≤ 1e5.
1 ≤ D ≤ 1e5.
1 ≤ E1 ≤ 1e5.
1 ≤ E2 ≤ 1e5.
1 ≤ F ≤ 1e5.
small
1 ≤ N ≤ 100.
1 ≤ K ≤ 20.
large
1 ≤ N ≤ 1e6.
1 ≤ K ≤ 1e4
題解
首先根據xycdef生成數組A。
對於小數據集暴力即可。O(k*n^3)
對於大數據集,可以考慮每個數對最后結果的貢獻,大力推推就可以出來了。
考慮第i次計算,則數組A中第j位計算的值為:A[j] * (N+1-j) * {1^i + 2^i + .... + j^i} ( j從1開始) 。直接枚舉的話復雜度O(k * n^2lgk) ,當然第j^i求和可以累加,能降到O(knlgk) 。
另一種思路是調換一下求和順序,則ans=sum_{i=1..j} {A[j] * (N+1-j) * sum_{i=1..k}{1^i + 2^i + .... + j^i}}。其中m^i求和可以用等比數列公式,再通過累加可以降到O(klgk)。(lgk為求冪時的復雜度)
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 1e9 + 7;
ll pw(ll a, ll b) {
ll ans = 1;
while (b) {
if (b&1) ans = ans * a % mod;
b /= 2;
a = a * a % mod;
//cout << ans << " " << a << "\n";
}
return ans;
}
ll calc(ll a, ll b) {
//cout << pw(a, b) << "\n";
ll ans = a * ((pw(a, b) - 1 + mod) % mod) % mod * pw(a-1, mod-2) % mod;
//cout << ans <<"\n";
}
ll solve() {
ll n, k;
cin >> n >>k;
vector<ll> nums(n+1);
ll x, y;
cin >> x >> y;
ll c,d,e1,e2,f;
cin >> c >> d >> e1 >> e2 >> f;
nums[1] = (x+y) % f;
for (int i = 2; i <= n; i++) {
ll tx = x, ty = y;
x = (c*tx+d*ty+e1) %f;
y = (d*tx+c*ty+e2) %f;
nums[i] = (x+y) % f;
}
ll ans = nums[1]*n%mod*k%mod;
ll sum = k;
//cout << ans <<"\n";
for (int i = 2; i <= n; i++) {
sum = (sum + calc(i, k)) % mod;
//cout << sum << "\n";
ans = (ans + nums[i] * (n+1-i) % mod * sum % mod) % mod;
//cout << i << " " << ans << "\n";
}
return ans;
}
int main() {
freopen("C-large-practice.in", "r", stdin);
freopen("C-large.out", "w", stdout);
int t;
cin >> t;
for (int tt = 1; tt <= t; tt++) {
std::cerr << tt << "\n";
printf("Case #%d: %lld\n", tt, solve());
}
return 0;
}