Educational Codeforces Round 168 (Rated for Div. 2) A - E
A. Strong Password
如果有两个相邻的字符相同,就在这两个字符就在中间插入一个不同的字符。
否则在第一个字符前面插入一个不同于第一个字符的字符
代码
点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;
const int N = 2e5 + 10,INF = 1e9,mod = 998244353;
int n,m,k;
void solve()
{
string s;cin >> s;
n = s.size();
s = " " + s;
char c = 'a';
FOR(i,2,n)
{
if (s[i] == s[i - 1])
{
FOR(j,1,i - 1) cout << s[j];
if (c == s[i]) c = 'b';
cout << c;
FOR(j,i,n) cout << s[j];
cout << '\n';
return;
}
}
if (s[1] == c) c = 'b';
cout << c;
FOR(i,1,n) cout << s[i];
cout << '\n';
}
signed main()
{
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
cin >> T;
while(T --)
{
solve();
}
return 0;
}
B. Make Three Regions
由于最多只会有一个联通块,所以答案只有在一种情况下才会增加:
第一行下标为 \(1\) ,第二行下标为 \(2\) ,当前位第 \(i\) 行第 \(j\) 列
\(i\backslash j\) | \(j-1\) | \(j\) | \(j+1\) |
---|---|---|---|
$ i $ | . | . | . |
\(3-i\) | x | . | x |
代码
点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;
const int N = 2e5 + 10,INF = 1e9,mod = 998244353;
int n,m,k;
char c[3][N];
void solve()
{
cin >> n;
FOR(i,1,2)
FOR(j,1,n)
cin >> c[i][j];
int ans = 0;
FOR(i,1,2)
FOR(j,2,n - 1)
if (c[i][j - 1] == '.' && c[i][j] == '.' && c[i][j + 1] == '.' &&
c[3 - i][j - 1] == 'x' && c[3 - i][j] == '.' && c[3 - i][j + 1] == 'x')
ans ++;
ANS;
}
signed main()
{
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
cin >> T;
while(T --)
{
solve();
}
return 0;
}
C. Even Positions
维护当前 '(' 比 ')' 多的数量,如果当前位置是奇数位的话,那么如果能放 ')' 就放上去,否则放上 '('。
对于每一个 '(' 可以开一个队列记录从左往右的位置,如果遇到 ')' 的话,这个 ')' 肯定是和队头的那个 '(' 匹配的,所以 ')' 肯定是放在越左边越好的。
代码
点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;
const int N = 2e5 + 10,INF = 1e9,mod = 998244353;
int n,m,k;
char c[N];
void solve()
{
cin >> n;
FOR(i,1,n) cin >> c[i];
queue<int> q;
int now = 0,ans = 0;
FOR(i,1,n)
{
if (c[i] == '(') now ++;
else if (c[i] == ')') now --;
else
{
if (now > 0) c[i] = ')',now --;
else c[i] = '(',now ++;
}
if (c[i] == '(') q.push(i);
else ans += i - q.front(),q.pop();
}
ANS;
}
signed main()
{
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
cin >> T;
while(T --)
{
solve();
}
return 0;
}
D. Maximize the Root
\(dp[i]\) 表示 \(i\) 节点及其子树可以取到的最大的最小值
转移方程
如果 \(i\) 节点是叶子节点 \(~~\) : \(dp[i] = a[i]\)
如果 \(i\) 节点不是叶子节点 : 设 $ t = min(dp[j])~~~~~(\forall j\in G[i]) ~$
答案是 $ a[1] + min(dp[i])~~~~~(\forall i\in G[1]) ~$
代码
点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;
const int N = 2e5 + 10,INF = 1e9,mod = 998244353;
int n,m,k;
int dp[N],a[N];
vector<int> G[N];
int ans;
void dfs(int u)
{
dp[u] = 1e18;
for(auto i : G[u])
{
dfs(i);
dp[u] = min(dp[u],dp[i]);
}
if (dp[u] == 1e18) dp[u] = a[u];
else
{
if (u == 1) ans = dp[u] + a[u];
else
{
if (dp[u] >= a[u]) dp[u] = (dp[u] + a[u]) / 2;
}
}
}
void solve()
{
cin >> n;
FOR(i,1,n) G[i].clear();
FOR(i,1,n) cin >> a[i];
FOR(i,2,n)
{
int fa;cin >> fa;
G[fa].emplace_back(i);
}
ans = 0;
dfs(1);
ANS;
}
signed main()
{
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
cin >> T;
while(T --)
{
solve();
}
return 0;
}
E. Level Up
先将所有的询问记录下来,然后枚举每个 \(k\) ,对于每个 \(k\) \(Monocarp\) 最多会提升 \(n / k\) 次等级,一共会提升 \(\sum_{k=1}^n n/k\approx n * log_2n\) 次等级,在提升等级的同时算出每一个询问的答案。
接下来需要考虑如何找到每个 \(k\) 的每个等级提升时的边界,假设当前左端点为 $ l$ 等级为 \(level\) ,可以用二分在 $l $ 到 $ n$ 之间找到最靠左的端点 \(r\) 使得 \(\sum_{i = l}^{r}(a[i] \geq level ) \geq k\) , 可以从 \(1\) 到 \(n\) 枚举 \(level\) ,然后更新每一个 \(k\) 的左端点,可以用 \(RMQ\) 来维护区间内大于等于当前 \(level\) 的 \(a[i]\) 的个数。
这里用的是树状数组,每次更新一个 \(level\) 的时候将权值为 \(level\) 的所以 \(a[i]\) 加入树状数组,这样就可以保证在树状数组中加入的点都是严格小于当前 \(level\) 的。
代码
点击查看代码
#include <bits/stdc++.h>
#define FOR(i,j,k) for(int i = (j);i <= (k);i ++)
#define ROF(i,j,k) for(int i = (j);i >= (k);i --)
#define PII pair<int,int>
#define int long long
#define ULL unsigned long long
#define db double
#define x first
#define y second
#define sp(x) fixed << setprecision(x)
#define all(g) g.begin(), g.end()
#define M(x) x %= mod, x += mod, x %= mod
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define Yes cout << "Yes\n"
#define No cout << "No\n"
#define ANS cout << ans << '\n'
#define de(p) cout << #p << ' ' << p << '\n'
#define END(i, n) (i == n ? '\n' : ' ')
using namespace std;
const int N = 2e5 + 10,INF = 1e9,mod = 998244353;
int n,m,k,Q;
int ans[N];
int yuan[N];
vector<int> alls[N];
struct treearray
{
vector<int> tre;int kk;
treearray(){}
treearray(int n){init(n);}
void init(int n){tre.resize(n);kk = n;}
int lowbit(int x){return x&(-x);}
int ask(int i){int ans=0; for(;i;i-=lowbit(i))ans+=tre[i];return ans;}
void add(int i,int d){for(;i<=kk;i+=lowbit(i))tre[i]+=d;}
};
void solve() {
cin >> n >> Q;
vector<int> a[N];
FOR(i, 1, n)
{
int x;cin >> x;
yuan[i] = x;
a[x].emplace_back(i);
}
priority_queue<PII, vector<PII >, greater<>> q[N];
FOR(t, 1, Q)
{
int i, x;cin >> i >> x;
q[x].push({i, t});
}//pos, id
treearray tr(2e5 + 1);
vector<PII> now[N];//pos,k
FOR(i, 1, n) now[1].emplace_back(1, i);
FOR(i, 1, n)
{
for (auto [pos, k]: now[i])
{
int l = pos, r = n;
while (l < r)
{
int mid = l + r >> 1;
if (mid - pos + 1 - (tr.ask(mid) - tr.ask(pos - 1)) >= k) r = mid;
else l = mid + 1;
}
int newpos = l;
while (q[k].size() && q[k].top().first <= newpos)
{
auto [qpos, id] = q[k].top();
q[k].pop();
if (yuan[qpos] >= i) ans[id] = 1;
else ans[id] = 0;
}
newpos ++;
if (newpos <= n)
{
now[i + 1].emplace_back(newpos,k);
}
}
//算 >= i的个数
for (auto j: a[i]) tr.add(j, 1);
}
FOR(i, 1, Q)
{
if (ans[i]) YES;
else NO;
}
}
signed main()
{
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T = 1;
// cin >> T;
while(T --)
{
solve();
}
return 0;
}