Codeforces Round #367 (Div. 2) 题解

题目链接:http://codeforces.com/contest/706


感想:唯一一次前四道题全部都有思路,而且能保证正确的一次CF。但是最后却只A了前两道水题,最后没能来得及写后两道题。也许是太晚了,脑袋不太清醒吧!后面才想到后两题的做法。回想一下,从18分钟写完B后,就开始打酱油到比赛末,最后只A两题,就愤愤不平。555555!


A.思路:水题。直接将各个点与源点比较算时间,求出最小值即可。详见代码。

#include 
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 
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 
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 
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<> 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;
}


你可能感兴趣的:(Codeforces)