2024-11-5-ABC378

ABC378

A - Pairing

题意

给定4个球。

问可以重复多少次以下操作:每次选两个相同颜色的球,然后丢弃。

思路

数一下每种颜色的球有几个,然后除2加一下。

#include <bits/stdc++.h>
using namespace std;
int cnt[4];
int main() {
	for (int i = 0; i < 4; i++) {
		int A;
		cin >> A;
		cnt[A - 1]++;
	}
	int ans = 0;
	for (int i = 0; i < 4; i++) {
		ans += cnt[i] / 2;
	}
	cout << ans << "\n";
	return 0;
}

B - Garbage Collection

题意

n种垃圾,第i种垃圾会在天数d收取,其中d满足\(d\%q_i=r_i\)。(就是隔qi加一个ri)

回答q个询问,每个询问问在第di天丢的第ti种垃圾,会在第几天被收取。如果当天丢且当天可收取,则会被收取。

image-20241105212821788

image-20241105212902774

思路

先算r=d % q[t],如果r<=r[t],那么再过r[t]-r天就好了,不然就要再等一个q[t]的时间。

#include <bits/stdc++.h>
using namespace std;
int q[105],r[105];
int main() {
	int n;
	cin >> n;
	for(int i=0;i<n;i++) 
		cin>>q[i]>>r[i];
	int Q;
	cin >> Q;
	while (Q--) {
		int t, d;
		cin >> t >> d;
		--t;
		int ans = (r[t] - d % q[t] + q[t]) % q[t];
		cout << d + ans << '\n';
	}
	return 0;
}

C - Repeating

题意

给定一个数组\(a\),构造相同长度的数组\(b\),满足\(b_i\)\(a_i\)上一次出现的位置,或者−1。

思路

用map记录每个\(a_i\)上次出现的位置,然后顺序输出map[a[i]]即可

#include <bits/stdc++.h>
using namespace std;
int main() {
	int n;
	cin >> n;
	map<int, int> pos;
	for (int i = 0; i < n; i++) {
		int x;
		cin >> x;
		if(pos.count(x)) cout<<pos[x]+1<<" ";
		else cout<<"-1 ";
		pos[x] = i;
	}
	
	return 0;
}

D - Count Simple Paths

题意

给定一张二维平面,有障碍物。

问方案数,从任意点出发,上下左右走,可以走kk步,不经过障碍物,且每个点只访问一次。

思路

暴力

#include<bits/stdc++.h>
using namespace std;
int dx[] = {0, 1, -1, 0};
int dy[] = {1, 0, 0, -1};
int h, w, k;
string s[15];
int ans;
bool vis[15][15];
bool check(int x, int y) {
	return (x >= 0 && y >= 0 && x < h && y < w && !vis[x][y] && s[x][y] == '.');
}
void dfs(int x, int y, int d) {
	if (d == k) {
		ans++;
		return;
	}
	vis[x][y] = 1;
	for (int i = 0; i < 4; i++) {
		int xx = x + dx[i], yy = y + dy[i];
		if (check(xx, yy)) {
			dfs(xx, yy, d + 1);
		}
	}
	vis[x][y] = 0;
}
int main() {
	cin >> h >> w >> k;
	for (int i = 0; i < h; i++)
		cin >> s[i];
	for (int i = 0; i < h; i++) {
		for (int j = 0; j < w; j++) {
			if (check(i, j))
				dfs(i, j, 0);
		}
	}
	cout << ans;
	return 0;
}

E - Mod Sigma Problem

题意

给定一个数组,求所有连续区间和modM后的总和(最后答案不取模)

image-20241105205245454

解法

求区间总和的经典方法就是前缀和,设\(S_i=(A_1+A_2+...+A_i)mod M\),就是前i项的总和,那么最后的答案就是求对于所有的连续区间\(l,r\)\((S_r-S_{l-1})modM\)的总和。

由于\(S_i\)都是小于M的,所以式子还可以改写一下。

image-20241105205308372

现在我们考虑固定r,然后计算出r不变l变的和,那我们要设\(X_r\)\(S_{l-1}>S_r\)的数量,这样我们就可以知道在r不变时加了多少个M,也就可以列出式子:

image-20241105205339052

不难发现 \(∑^r_{l=1}S_{l-1}\)是S数组的前缀和,也就是说只要能快速求出\(X_r\)问题就解决了。

预处理出前缀和数组后,问题就是查询当前数前面有多少个数大于当前数,这个问题可以用树状数组搞定。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 200005;
struct FenwickTree {
	vector<ll> tree;
	int n;
	FenwickTree(int size) {
		n = size;
		tree.resize(size + 1, 0);
	}

	void update(int index, int delta) {
		for (++index; index <= n; index += index & -index) {
			tree[index] += delta;
		}
	}

	int query(int index) {
		int sum = 0;
		for (++index; index > 0; index -= index & -index) {
			sum += tree[index];
		}
		return sum;
	}
};

vector<ll> countGreaterThan(const vector<ll>& nums) {
	int n = nums.size();

	// 建立一个副本以进行排序和离散化
	vector<ll> sorted_nums = nums;
	sort(sorted_nums.begin(), sorted_nums.end());

	vector<ll> result(n);
	FenwickTree fenwickTree(n);

	// 从后到前遍历
	for (int i = 0; i < n; i++) {
		// 计算当前数的离散化索引
		int index = lower_bound(sorted_nums.begin(), sorted_nums.end(), nums[i]) - sorted_nums.begin();
		// 查询前面有多少个数是小于等于当前数
		result[i] = fenwickTree.query(n - 1) - fenwickTree.query(index);
		// 更新树状数组,增加当前数的出现次数
		fenwickTree.update(index, 1);
	}

	return result;
}

int n;
ll m, a[maxn];
vector<ll> s;

int main() {
	cin >> n >> m;
	s.resize(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		s[i] = (s[i - 1] + a[i]) % m;
	}
	vector<ll> x = countGreaterThan(s);
	ll ans = 0, sum = 0;
	for (int i = 1; i <= n; i++) {
		ans += s[i] * i - sum + m * x[i];
		sum += s[i];
	}
	cout << ans;
	return 0;
}
posted @ 2024-11-30 23:27  ~清渠~  阅读(0)  评论(0编辑  收藏  举报