题目链接: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;
}