題目鏈接:http://codeforces.com/contest/706
感想:唯一一次前四道題全部都有思路,而且能保證正確的一次CF。但是最後卻只A了前兩道水題,最後沒能來得及寫後兩道題。也許是太晚了,腦袋不太清醒吧!後面纔想到後兩題的做法。回想一下,從18分鐘寫完B後,就開始打醬油到比賽末,最後只A兩題,就憤憤不平。555555!
A.思路:水題。直接將各個點與源點比較算時間,求出最小值即可。詳見代碼。
#include <bits/stdc++.h>
using namespace std;
double a, b;
int n;
int main(){
//ios::sync_with_stdio(false);
//cin.tie(0);
cin >> a >> b >> n;
double ans = INT_MAX;
double x, y, v;
while (n--){
cin >> x >> y >> v;
ans = min(ans, sqrt((x-a)*(x-a)+(y-b)*(y-b))/v);
}
printf("%.8f\n", ans);
return 0;
}
B.思路:排序後二分查找或者樹狀數組可以解決。這裏用的是樹狀數組,樹狀數組下標是輸入的數,存儲的是某區間小於等於給定數的個數。詳見代碼。注意:樹狀數組的寫法,要注意詢問時,給出的數可能大於最大下標。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int sum[maxn];
int n, q;
int lowbit(int x){
return x&(-x);
}
void add(int p){
while (p < maxn){
++sum[p];
p += lowbit(p);
}
}
int query(int p){
int ans = 0;
while (p > 0){
ans += sum[p];
p -= lowbit(p);
}
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
int num;
while (n--){
cin >> num;
add(num);
}
cin >> q;
while (q--){
cin >> num;
if (num >= maxn)
num = maxn-1;
cout << query(num) << endl;
}
return 0;
}
C.思路:一開始準備枚舉一遍後,得出結果。後來發現有問題,得到的結果明顯不對。後來再仔細分析一下,發現是一道簡單DP題,狀態轉移比較簡單,不多解釋。詳見代碼。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;
const ll inf = 0x3f3f3f3f3f3f3f3fll;
ll dp[maxn][2];
int cost[maxn];
string s[maxn], t[maxn];
int n;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for (int i=1; i<=n; ++i)
cin >> cost[i];
for (int i=1; i<=n; ++i){
cin >> s[i];
t[i] = s[i];
reverse(t[i].begin(), t[i].end());
dp[i][0] = dp[i][1] = inf;
}
dp[1][0] = 0;
dp[1][1] = cost[1];
for (int i=2; i<=n; ++i){
if (s[i] >= s[i-1])
dp[i][0] = dp[i-1][0];
if (s[i] >= t[i-1])
dp[i][0] = min(dp[i][0], dp[i-1][1]);
if (t[i] >= s[i-1])
dp[i][1] = dp[i-1][0]+cost[i];
if (t[i] >= t[i-1])
dp[i][1] = min(dp[i][1], dp[i-1][1]+cost[i]);
}
ll ans = min(dp[n][0], dp[n][1]);
cout << (ans==inf ? -1 : ans) << endl;
return 0;
}
D.思路:一道字典樹的題。將要插入的數的二進制位倒着建樹(爲什麼?因爲異或時高位儘量大,結果才儘量大),即高位在深度低的節點上。用一個數組記錄經過各個節點的數的個數,插入時,每經過一個點,將節點的這個值加一,刪除時,則減一。查找時,當前節點的這個值大於0,說明有數經過。對於要查找的這個數的高位,如果是1,要使異或值儘量大,那麼就要往0的地方走,反之,往1的地方走,實在沒辦法走,只有按原路徑走啦。詳見代碼。注意:0永遠在樹中。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3000005;
int child[maxn][2], val[maxn];
int q, sz=1;
string op;
void _insert(int x){
int pos = 0;
for (int i=29; i>=0; --i){
int id = (x>>i)&1;
if (!child[pos][id])
child[pos][id] = sz++;
pos = child[pos][id];
++val[pos];
}
}
void _delete(int x){
int pos = 0;
for (int i=29; i>=0; --i){
int id = (x>>i)&1;
pos = child[pos][id];
--val[pos];
}
}
int query(int x){
int ans=0, pos=0;
for (int i=29; i>=0; --i){
int id = (x>>i)&1;
if (id == 1){
if (child[pos][0] && val[child[pos][0]]){
ans += 1<<i;
pos = child[pos][0];
}
else
pos = child[pos][1];
}
else{
if (child[pos][1] && val[child[pos][1]]){
ans += 1<<i;
pos = child[pos][1];
}
else
pos = child[pos][0];
}
}
return ans;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> q;
int num;
_insert(0);
while (q--){
cin >> op >> num;
if (op[0] == '+')
_insert(num);
else if (op[0] == '-')
_delete(num);
else
cout << query(num) << endl;
}
return 0;
}