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;
}