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;
}
简单来说就是求两标记点的最大距离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;
}
终于结束了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】