CSP模拟-10

全是期望,这是捅期望窝了????
emmm.......今天考试爆炸,QAQ心态直接炸

T1 Because

等等,这是。。。。。游走?!?!!!!窝似沙币,没记住之前的题。。。。

当我打完模拟赛后:沃日,不tm的是游走,是一个再简单不过的概率题,差不多学过高一下概率单元的人都会的题,我不会!!!!!!!想死的心都有了。所以我又没有读懂题。。。我真服了。。。

首先,有 \(\frac{1}{n}\) 的概率选到最中间的点,则选到这个点时的期望是 \(\frac{1}{n}\)。有另外 \(\frac{n-1}{n}\) 的概率选到菊花图周围的点,在我们此时选到的除了这个点外的点中有 \(\frac{1}{n-1}\) 的概率选到中心的点,此时期望为 \(\frac{n-1}{n} \cdot \frac{1}{n-1}\) ;我们这时选到除本个点以外的周围点的概率是 \(\frac{n-2}{n-1}\),期望为 \(\frac{n-1}{n} \cdot \frac{2(n-2)}{n-1}\)。所以三个式子相加为 \(\frac{2n-2}{n}\)。注意特判点数为 \(2\) 的情况。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

int t, n;

int main() {
	cin >> t;
	while (t --) {
		cin >> n;
		if (n == 2) {
			printf("1.000000000 1.000000000\n");
		}
		else {
			printf("%.9lf 2.000000000\n", ((double)n * 2.0 - 2.0) / ((double)n));
		}
	}
	return 0;
} 

T2 Love

其实说实话这个题真不难,但我从来没有捞到过分,也许是我太菜了吧

将所有输入的元素记录,并记录输入的元素在哪个集合,然后将所有输入的元素按数值升序排序。用双指针维护一个最小区间使其集合个数刚好小于 \(k\),在每次左指针右移(也就是现在双指针包含的元素的集合个数超过 \(k\))时更新 \(ans\) 值。

#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <cstdio>

using namespace std;

int k, n, ans = 2000000000;
int barrel[1000100], set_num;

struct Number {
	int pos, num;
	bool operator < (const Number &b) const {
		return num < b.num;
	}
}c[4001000];

int main() {
	scanf("%d", &k);
	for (int i = 1, sum; i <= k; ++ i) {
		scanf("%d", &sum);
		for (int j = 1 + n; j <= sum + n; ++ j) {
			scanf("%d", &c[j].num);
			c[j].pos = i;
		}
		n += sum;
	}
	sort(c + 1, c + 1 + n);
	for (int l = 1, r = 1; r <= n; ++ r) {
		if (barrel[c[r].pos] == 0) 
			set_num ++;
		barrel[c[r].pos] ++;
		while (set_num == k) {
			if (set_num == k) {
				ans = min(ans, c[r].num - c[l].num);
			} 
			if (barrel[c[l].pos] == 1) {
				set_num --;
			}
			barrel[c[l].pos] --;
			l ++;
		}
	}
	cout << ans << endl;
	return 0;
}

T3

T4 Everyday

题目要输出的是选出的宝石的值的种类有多少种

将每段区间直接硬并,如若输入 \(a_i = 1, b_i = 3\)\(a_{i+1} = 2, b_{i+1} = 4\) 合并后是\(a_1 = 1, b_1 = 3\)\(a_2 = 2, b_2 = 4\)\(a_3 = 0, b_3 = 0\)\(a_4 = 3, b_4 = 7\)。第一个序列是之选 \(a_i, b_i\),第二个序列是只选 \(a_{i+1}, b_{i+1}\),第三个序列是都不选,第四个序列是都选。用线段树维护在 \(l, r\) 的宝石序列所构成的集合就行。

时间复杂度,因为是随的,所以基本上线段树上每个节点是 \(O(1)\) 的范围,不会炸

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>

using namespace std;

long long n, q;
long long opt, k, a, b, L, R, sum;
pair<long long, long long> interval[310000];
vector <pair<long long, long long> > ASK;

struct Segment_Tree {
	long long l, r;
	vector <pair<long long, long long> > vec;
}tree[300000];

struct SegmentTree {
	#define lid id << 1 
	#define rid id << 1 | 1
	vector<pair<long long, long long> > Pushup(vector<pair<long long, long long> > &l, vector<pair<long long, long long> > &r) {	
		//硬并,将l和r里面的集合一个一个对应相加	
		pair <long long, long long> tem1, tem2;
		vector<pair<long long, long long> > now, ans;
		for (int i = 0; i < (int)l.size(); ++ i) {
			for (int j = 0; j < (int)r.size(); ++ j) {
				tem1 = l[i], tem2 = r[j];
				now.push_back(make_pair(tem1.first + tem2.first, tem1.second + tem2.second));
			}
		}
		now.shrink_to_fit();
		bool flag[now.size()];
		for (int i = 0; i < (int)now.size(); ++ i) {
			flag[i] = false;
		}
		sort(now.begin(), now.end());
		//排序后合并now内有重叠的区间 
		for (int i = 1; i < (int)now.size(); ++ i) {
			tem1 = now[i - 1], tem2 = now[i];
			if (tem1.first <= tem2.first && tem2.first <= tem1.second) {
				tem1.second = max(tem1.second, tem2.second);
				if (flag[i - 1] == true) {
					ans.pop_back();
					flag[i - 1] = false;
				}
				ans.push_back(tem1);
				now[i] = tem1;
				flag[i] = true;
			}
			else {
				if (flag[i - 1] == false) {
					ans.push_back(tem1);
					flag[i - 1] = true;//
				}
				ans.push_back(tem2), flag[i] = true;				
			}
		}
		ans.shrink_to_fit();
		return ans;
//		for (set<pair<long long, long long> >::iterator it1 = tree[lid].Set.begin(); it1 != tree[lid].Set.end(); it1 ++) {
//			for (set<pair<long long, long long> >::iterator it2 = tree[rid].Set.begin(); it2 != tree[rid].Set.end(); it2 ++) {
//				tem1 = *it1, tem2 = *it2;
//				tem1.first = tem1.first + tem2.first;
//				tem1.second = tem1.second + tem2.second;
//				tree[id].Set.insert(tem1);
//			}
//		}
//		pair<long long, long long> *las, *now;
//		for (set<pair<long long, long long> >::iterator it = tree[id].Set.begin(); it != tree[id].Set.end(); ++ it) {
//			if (it ==  tree[id].Set.begin()) continue;
//			las = *prev(it);
//		}
	}
	void BuildTree(int id, int l, int r) {
		tree[id].l = l, tree[id].r = r;
		if (l == r) {
			tree[id].vec.push_back(make_pair(0, 0));
			tree[id].vec.push_back(interval[l]);
			//注意要后插interval,因为后面修改的时候要弹出interval 
			return;
		}
		int mid = l + ((r - l) >> 1);
		BuildTree(lid, l, mid);
		BuildTree(rid, mid + 1, r);
		tree[id].vec = Pushup(tree[lid].vec, tree[rid].vec);
		tree[id].vec.shrink_to_fit();
		//正常建树 
		return;
	} 
	void Update(int id, int l, int r, int pos, pair<long long, long long>upd) {
		if (l == r) {
			tree[id].vec.pop_back();
			tree[id].vec.push_back(upd);
			//更新弹出后在插入 
			return;
		}
		int mid = l + ((r - l) >> 1);
		if (pos <= mid) Update(lid, l, mid, pos, upd);
		else Update(rid, mid + 1, r, pos, upd);
		tree[id].vec.clear();
		tree[id].vec = Pushup(tree[lid].vec, tree[rid].vec);
		//pushup 
		tree[id].vec.shrink_to_fit();
		return;
	}
	vector<pair<long long, long long> > Query(int id, int l, int r, int ask_l, int ask_r) {
		if (ask_l <= l && r <= ask_r) {
			return tree[id].vec;
		}
		int mid = l + ((r - l) >> 1);
		vector<pair<long long, long long> > tem1, tem2, ask;
		tem1.push_back(make_pair(0, 0)), tem2.push_back(make_pair(0, 0));
		//注意初始化 
		if (ask_l <= mid) tem1 = Query(lid, l, mid, ask_l, ask_r);
		if (mid + 1 <= ask_r) tem2 = Query(rid, mid + 1, r, ask_l, ask_r);
		return Pushup(tem1, tem2);
	}
}Tree;

int main() {
	scanf("%lld%lld", &n, &q);
	for (int i = 1; i <= n; ++ i) {
		scanf("%lld%lld", &a, &b);
		interval[i] = make_pair(a, b);
	}
	Tree.BuildTree(1, 1, n);
	while (q --) {
		scanf("%lld", &opt);
		if (opt == 1) {
			scanf("%lld%lld%lld", &k, &a, &b);
			Tree.Update(1, 1, n, k, make_pair(a, b));
		}
		else {
			scanf("%lld%lld", &L, &R);
			ASK = Tree.Query(1, 1, n, L, R);
			for (int i = 0; i < (int)ASK.size(); ++ i) {
				sum += (ASK[i].second - ASK[i].first + 1);
			}
			cout << sum << endl;
			sum = 0;
		}
	}
	return 0;
}
posted @ 2023-08-01 06:36  觉清风  阅读(14)  评论(0编辑  收藏  举报