比赛链接:

https://ac.nowcoder.com/acm/contest/42105

A.Adjacent Swapping

题意:

给定一个字符串 \(s\),要求将它变成 \(xx\)(保证可以分),即拆成两个相同的子串,每次可以交换相邻的两个元素,问最少进行几次操作可以达到目的。

思路:

将整个过程拆成两步,先将字母移到属于自己的区间,然后再考虑让两个字符串相同。
将字母移动到自己的区间,首先要计算每个区间各个字母分别有多少个,将这些字母全部移动到前半部分,剩下的放到后半部分。
接着要将两个字符串变成一样,可以考虑将第一个字符串作为模板串,第一个编号为 1,第二个为 2...以此类推,然后将第二个字符串按照模板串转化掉。
现在,第一个字符串就是 1 2 3... \(n\),第二个字符串是 1 到 \(n\) 的排列,让两个变成一样,即计算逆序对的数量,树状数组或者归并排序都可以实现。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
struct fwt{
	int n;
	vector <int> a;
	fwt(int n) : n(n), a(n + 1) {}
	LL sum(int x){
		LL res = 0;
		for (; x; x -= x & -x)
			res += a[x];
		return res;
	}
	void add(int x, LL k){
		for (; x <= n; x += x & -x)
			a[x] += k;
	}
	LL query(int x, int y){
		return sum(y) - sum(x - 1);
	}
};
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n;
	string s;
	cin >> n >> s;
	vector <int> cnt(26);
	for (int i = 0; i < n; i ++ )
		cnt[s[i] - 'a'] ++ ;
	for (int i = 0; i < 26; i ++ )
		cnt[i] /= 2;
	LL ans = 0;
	vector <int> a, b;
	for (int i = 0; i < n; i ++ ){
		if (cnt[s[i] - 'a']){
			cnt[s[i] - 'a'] -- ;
			ans += i - a.size();
			a.push_back(s[i] - 'a');
		}
		else b.push_back(s[i] - 'a');
	}
	vector <int> to(n / 2), pos(26, n / 2);
	for (int i = n / 2 - 1; i >= 0; i -- ){
		to[i] = pos[a[i]];
		pos[a[i]] = i;
	}
	vector <int> p(26, -1);
	for (int i = 0; i < n / 2; i ++ ){
		if (p[a[i]] != -1) continue;
		p[a[i]] = i;
	}
	vector <int> c(n / 2);
	for (int i = 0; i < n / 2; i ++ ){
		c[i] = p[b[i]];
		p[b[i]] = to[p[b[i]]];
	}
	fwt f(n / 2);
	for (int i = 0; i < n / 2; i ++ ){
		f.add(c[i] + 1, 1);
		ans += i + 1 - f.query(1, c[i] + 1);
	}
	cout << ans << "\n";
	return 0;
}

B.Business Website

题意:

\(n\) 个点,满足拓扑图性质,每个点只会到比自己编号大的点,每个点到下一个点的概率已知,问从 1 到其他点的概率是多少。

思路:

\(u\) 的概率为 \(x\),到达点 \(v\) 的概率为 \(w\),那么 \(v\) 的概率就会加 \(x * w\),同时 \(u\) 的概率会减去 \(x * w\)

代码:

#include <bits/stdc++.h>
using namespace std;
void solve(){
	int n;
	cin >> n;
	vector < vector < pair <int, double> > > G(n + 1);
	vector <double> ans(n + 1);
	vector <int> in(n + 1);
	for (int u = 1; u <= n - 1; u ++ ){
		int k;
		cin >> k;
		for (int i = 1; i <= k; i ++ ){
			int v;
			double w;
			cin >> v >> w;
			G[u].push_back({v, w});
		}
	}
	ans[1] = 1;
	for (int u = 1; u <= n; u ++ ){
		double x = ans[u];
		for (auto [v, w] : G[u]){
			ans[v] += x * w;
			ans[u] -= x * w;
		}
	}
	for (int i = 1; i <= n; i ++ )
		cout << fixed << setprecision(10) << ans[i] << " \n"[i == n];
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

F.Factor Difference

题意:

\(T\) 组测试,每组告诉 \(n\),要求找到一个正整数,至少有 8 个因数,且每两个因数之间差值至少为 \(n\)

思路:

因为因数分解后为若干质因数,所以只需要找到最小的三个质因数 + 一个 1,让它们的差值至少为 \(n\),就可以保证至少八个因数了(三个数的组合,就可以产生 4 个数,合起来总共八个)。
通过欧拉筛跑一下,然后求解即可。1 要特判。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 1e6 + 10;
bool st[N];
int prime[N], cnt;
void sieve(int n){
	st[1] = true;
	for (int i = 2; i <= n; i ++ ){
		if (!st[i]) prime[ ++ cnt] = i;
		for (int j = 1; j <= cnt && i * prime[j] <= n; j ++ ){
			st[i * prime[j]] = true;
			if (i % prime[j] == 0) break;
		}
	}
}
void solve(){
	int n;
	cin >> n;
	if (n == 1){
		cout << "24\n";
		return;
	}
	vector <LL> a;
	a.push_back(1);
	for (int i = 1; i <= cnt; i ++ ){
		if (prime[i] >= a.back() + n) a.push_back(prime[i]);
		if (a.size() >= 4) break;
	}
	LL ans = 1;
	for (auto x : a)
		ans *= x;
	cout << ans << "\n";
}
int main(){
	sieve(N - 10);
	int T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

H.Hacking Interview Solution

题意:

给定 \(m\) 个长为 \(m\) 的序列,问有多少对相同的序列。

思路:

\(map\) 中套一个 \(vector\) 可以过。
也可以对序列进行 \(hash\),然后存起来求解。

代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
void solve(){
	int n, m;
	cin >> n >> m;
	vector <int> a(n);
	for (int i = 0; i < n; i ++ )
		cin >> a[i];
	map <vector <int>, LL> Map;
	for (int i = 0; i < m; i ++ ){
		vector <int> o(n);
		for (int j = 0; j < n; j ++ )
			cin >> o[j];
		Map[o] ++ ;
	}
	LL ans = 0;
	for (auto [t, x] : Map)
		ans += x * (x - 1) / 2;
	cout << ans << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

K.Kooky Clock

题意:

有三条线段,第一条长 \(l_1\),它 \(t_1\) 秒就可以转一圈,第二条长 \(l_2\),它 \(t_2\) 秒就可以转一圈,第三条长 \(l_3\),它 \(t_3\) 秒就可以转一圈。
第一条线段头连着原点,尾连着第二条线段的头,第二条线段的尾连着第三条线段,现在经过了 \(T\) 秒(线段顺时针转),问第三条线段的尾的坐标。

思路:

用三角函数。

思路:

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
int main(){
	double T;
	cin >> T;
	vector <double> l(3), t(3);
	for (int i = 0; i < 3; i ++ )
		cin >> l[i];
	for (int i = 0; i < 3; i ++ )
		cin >> t[i];
	double x = 0, y = 0;
	for (int i = 0; i < 3; i ++ )
		x += l[i] * sin(T / t[i] * 2 * pi);
	for (int i = 0; i < 3; i ++ )
		y += l[i] * cos(T / t[i] * 2 * pi);
	cout << fixed << setprecision(10) << x << " " << y << "\n";
	return 0;
}
posted on 2022-10-20 10:40  Hamine  阅读(410)  评论(0编辑  收藏  举报