Codeforces Round 903 (Div. 3) D-G

D. Divide and Equalize
思路:
1.某个数除以x,某个数再乘以x,可发现数组总的乘积没有变化
2.也就是说,要使数组中的每一个元素相同,它们总的质因子应该满足:某个质因子的数量%n==0

赛后才发现,痛失上大分

E. Block Sequence
简单的dp
dp[i],表示删除这个数字后的最小删除次数
可以正的枚举,也可以倒着来
转移方程为dp[i]=min(dp[i],dp[i+a[i]+1]);

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
void solve() {
	int n;
	cin >> n;
	vector<int> a(n + 1),d(n+3);
	for (int i = 1; i <= n; i++) cin >> a[i];
	d[n + 1] = 0;
	d[n] = 1;
	for (int i = n - 1; i >= 1; i--) {//倒着枚举
		d[i] = d[i + 1]+1;
		if (i + a[i] <= n) {//如果不出界
			d[i] = min(d[i], d[i + a[i]+1]);//选着删除,或者不删除。不删除,则最小次数取决上一个
		}
	}
	cout << d[1] << '\n';
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

F. Minimum Maximum Distance

简单来说就是求两标记点的最大距离len,ans为(len+1)/2 (向上取整)
问题求的是点i距离标记点的最大距离f[i]的最小值
了解:
1.k==1时,ans=0
自己距离自己为0

2.k==2时,答案在两标记点之间的位置:外面的点距离最大一定大于中间的点

3.k>2
依旧可以证明答案的位置在两标记点的最大距离之间的点

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 2e5 + 10;
int vis[N],len;
int pos;
vector<int> g[N];
void dfs(int u, int fa, int l) {
	if (vis[u] && l > len) pos = u, len = l;//如果是标记点,且距离变大则更新最大标记点
	for (auto v : g[u]) {
		if (v == fa) continue;
		dfs(v, u, l + 1);
	}
}
void solve() {
	memset(vis, 0, sizeof vis);
	int n, k;
	cin >> n >> k;
	for (int i = 1; i <= n; i++) g[i].clear();
	for (int i = 1; i <= k; i++) cin >> pos, vis[pos] = 1;
	for (int i = 1; i < n; i++) {
		int x, y;
		cin >> x >> y;
		g[x].push_back(y);
		g[y].push_back(x);
	}
	len = 0;
	dfs(pos, 0, 0);//一个标记点到其他标记点的最大距离
	dfs(pos, 0, 0);//寻找最大距离
	cout << (len + 1) / 2 << "\n";
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

G. Anya and the Mysterious String
差分+树状数组+set
判断是否美丽:
1.如果相邻相等肯定不美丽(简称二回文串):aa
2.隔一位产生回文串(简称三回文串):aba

加x
1.对区间加,可以转换成树状数组的差分
区间l,r
2.很明显区间内的状态不会发生变化,主要是端点两边:
2.1对二回文串:[l-1,l],[r,r+1];
2.2对三回文串:[l-2,l],[l-1,l+1],[r-1,r+1],[r,r+2]

查询:l,r
利用set,s2:二回文串的位置,记录l,表示[l,l+1]是回文串;s3:三回文串的位子,记录l,表示[l-1,l+1]是回文串
1.对于s2,如果[l,l+1]在区间里面,则是不美丽的
2.对于s3,如果[l-1,l+1]在区间里面,则是不美丽的
3.反之区间是美丽的

注意细节,都在代码里

细节
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 2e5 + 10;
int t[N],n,m;
void add(int x,int k) {
	k %= 26;//一定要化简,不然一直加上去会爆int
	for (; x <= n; x += (x & -x)) {
		t[x] += k;
	}
}
LL get(int x) {
	LL ans = 0;
	for (; x; x -= (x & -x)) {
		ans =(ans+t[x])%26;
	}
	return ans;
}
set<int> s2, s3;
void check(int x) {
	if (x  < 1 || x  >=n) return;//不在区间范围内
	//两个回文
	if (x + 1 <= n) {
		LL  x2 = get(x)%26, x3 = get(x + 1)%26;//单点查询
		if (x2 != x3) s2.erase(x);
		else s2.insert(x);
	}
	//三个回文
	if(x-1>0&&x+1<=n){
		LL x2 = get(x - 1)% 26, x3 = get(x + 1) % 26;
		if (x2 != x3 ) s3.erase(x);//已经不同,删除
		else s3.insert(x);//相同插入
	}
}
void solve() {
	cin >> n >> m;
	string s;
	cin >> s;
	s = " " + s;
	//每次记得清空
	memset(t, 0, sizeof t);
	s2.clear();
	s3.clear();

	for (int i = 1; i <= n; i++) //差分
	{
		int x = s[i] - 'a';
		add(i, x);
		add(i + 1, -x);
	}
	for (int i = 1; i < n; i++) {
		if (s[i] == s[i + 1]) {
			s2.insert(i);//如果相邻相等属于二回文串
		}
		if (i-1>=1&&s[i - 1] == s[i + 1]) {
			s3.insert(i);//同理,属于三回文串
		}
	}
	while (m--) {
		int op, l, r;
		cin >> op >> l >> r;
		if (op == 1) {
			int x;
			cin >> x;
			add(l, x), add(r + 1, -x);//区间修改
			for (int i = -1; i <= 1; i++) {//对俩端点查看
				check(l + i);
				check(r + i);
			}
		}
		else {
			int f = 0;
			auto it = s2.lower_bound(l);
			if (it != s2.end() && *it < r) {
				f = 1;
			}
			it = s3.upper_bound(l);//要大于,不然会出界,具体看自己的逻辑
			if (it != s3.end() && *it < r) {
				f = 1;
			}
			cout << (f ? "NO\n" : "YES\n");
		}
	}

}

int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t;
	cin >> t;
	while (t--) {
		solve();
	}
	return 0;
}

终于结束了

posted @   不o凡  阅读(86)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示