here.
E 先咕了,不知道贪心怎么假的。
C
考虑最终合法的字符串,形如:
\[1,2,2,2,\cdots,2,2,2,3
\]
然后考虑对于每对 \(1,3\) 对答案的贡献是,它们中间 \(2\) 的个数,记为 \(cnt\),\(2^{cnt}-1\)。
然后考虑从左往右扫,每次遇到 \(1\) 往 ds 里加入一个 \(1\),遇到 \(2\) 全局乘 \(2\),遇到 \(3\) 计算答案。
可以用线段树维护,复杂度 \(O(n \log n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int t,n,a[200005],cnt,ans;
int val[400005],tag[400005],ls[400005],rs[400005],dcnt,rt;
void pushup(int x){val[x]=(val[ls[x]]+val[rs[x]])%mod;
}
void pushdown(int x){if(tag[x]==1) return;val[ls[x]]=val[ls[x]]*tag[x]%mod;val[rs[x]]=val[rs[x]]*tag[x]%mod;tag[ls[x]]=tag[ls[x]]*tag[x]%mod;tag[rs[x]]=tag[rs[x]]*tag[x]%mod;tag[x]=1;
}
void build(int l,int r,int &x){x=++dcnt;if(l==r) return;int mid=(l+r)>>1;build(l,mid,ls[x]);build(mid+1,r,rs[x]);pushup(x);
}
void modify1(int l,int r,int pos,int k,int x){if(l==r){val[x]=k;return;}int mid=(l+r)>>1;pushdown(x);if(pos<=mid) modify1(l,mid,pos,k,ls[x]);else modify1(mid+1,r,pos,k,rs[x]);pushup(x);
}
void modify2(int l,int r,int ql,int qr,int k,int x){if(ql<=l && r<=qr){val[x]=val[x]*k%mod;tag[x]=tag[x]*k%mod;return;}pushdown(x);int mid=(l+r)>>1;if(ql<=mid) modify2(l,mid,ql,qr,k,ls[x]);if(qr>=mid+1) modify2(mid+1,r,ql,qr,k,rs[x]);pushup(x);
}
int query(int l,int r,int ql,int qr,int x){if(ql<=l && r<=qr) return val[x];pushdown(x);int mid=(l+r)>>1,ans=0;if(ql<=mid) ans=(ans+query(l,mid,ql,qr,ls[x]))%mod;if(qr>=mid+1) ans=(ans+query(mid+1,r,ql,qr,rs[x]))%mod;return ans;
}
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>t;while(t--){cin>>n;build(1,n,rt);for(int i=1;i<=n;i++){cin>>a[i];if(a[i]==1){modify1(1,n,i,1,rt);cnt++;}else if(a[i]==2){modify2(1,n,1,i,2,rt);}else{ans=(ans+query(1,n,1,i,rt)-cnt+mod)%mod;}}cout<<ans<<'\n';ans=0;for(int i=1;i<=dcnt;i++){val[i]=tag[i]=ls[i]=rs[i]=0;}dcnt=cnt=0;}
}
D
考虑将两边相等的字符去掉之后,需要翻转的子串是一个前缀或者后缀。
然后就可以二分检查合法性了。
复杂度 \(O(n \log n)\)。
#include <bits/stdc++.h>
using namespace std;
int main() {int t;cin >> t;while (t--) {string s;cin >> s;int n = s.size();int i = 0;while (i < n / 2 && s[i] == s[n - i - 1]) ++i;n -= 2 * i;s = s.substr(i, n);int ans = n;for (int z = 0; z < 2; ++z) {int l = 0, r = n;while (l <= r) {int m = (l + r) / 2;vector<int> cnt(26);for (int i = 0; i < m; ++i)cnt[s[i] - 'a']++;bool ok = true;for (int i = 0; i < min(n / 2, n - m); ++i) {char c = s[n - i - 1];if (i < m) {ok &= cnt[c - 'a'] > 0;cnt[c - 'a']--;} else {ok &= (c == s[i]);}}for (auto x : cnt)ok &= (x % 2 == 0);if (ok) {r = m - 1;} else {l = m + 1;}}ans = min(ans, r + 1); reverse(s.begin(), s.end());}cout << ans << '\n';}
}
F
考虑每一个时刻,答案为 \(A\) 的连通块数量 与 \(A \cup B\) 的连通块之差。
然后直接上线段树分治 + 可撤销并查集算就行了。
复杂度 \(O(n \log n \alpha(n))\)。
常数巨大。
#include<bits/stdc++.h>
#define int long long
using namespace std;
char op;
int n,m,x,y,id,cnt[3],ans[3][400005];
map<int,int> mp[2];
struct node{int x,y;
};
vector<node> v[800005][3];
struct line{int x,y,fa,siz;
};
stack<line> s[3];
int ls[800005],rs[800005],dcnt,rt;
void build(int l,int r,int &x){x=++dcnt;if(l==r) return;int mid=(l+r)>>1;build(l,mid,ls[x]);build(mid+1,r,rs[x]);
}
void modify(int l,int r,int ql,int qr,int u,int y,int op,int x){if(ql<=l && r<=qr){v[x][op].push_back((node){u,y});return;}int mid=(l+r)>>1;if(ql<=mid) modify(l,mid,ql,qr,u,y,op,ls[x]);if(qr>=mid+1) modify(mid+1,r,ql,qr,u,y,op,rs[x]);
}
int fa[3][400005],siz[3][400005];
void init(){for(int i=1;i<=n;i++){fa[0][i]=i;fa[1][i]=i;fa[2][i]=i;siz[0][i]=1;siz[1][i]=1;siz[2][i]=1;}
}
int find(int op,int x){if(fa[op][x]==x) return x;else return find(op,fa[op][x]);
}
void merge(int op,int x,int y){x=find(op,x);y=find(op,y);if(x==y) return;if(siz[op][x]>siz[op][y]) swap(x,y);s[op].push((line){x,y,fa[op][x],siz[op][y]});fa[op][x]=y;siz[op][y]+=siz[op][x];cnt[op]--;
}
void dfs(int l,int r,int op,int x){int now=s[op].size();for(int i=0;i<v[x][op].size();i++){merge(op,v[x][op][i].x,v[x][op][i].y);}if(l==r){ans[op][l]=cnt[op];}else{int mid=(l+r)>>1; dfs(l,mid,op,ls[x]);dfs(mid+1,r,op,rs[x]);}while(s[op].size()!=now){fa[op][s[op].top().x]=s[op].top().fa;siz[op][s[op].top().y]=s[op].top().siz;s[op].pop();cnt[op]++;}
}
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n>>m;cnt[0]=cnt[1]=cnt[2]=n;build(1,m,rt);init();for(int i=1;i<=m;i++){cin>>op>>x>>y;if(x>y) swap(x,y);int id=x*(n+1)+y; if(op=='A'){if(mp[0][id]){modify(1,m,mp[0][id],i-1,x,y,0,rt);modify(1,m,mp[0][id],i-1,x,y,2,rt);mp[0].erase(id);}else{mp[0][id]=i;}}else{if(mp[1][id]){modify(1,m,mp[1][id],i-1,x,y,1,rt);modify(1,m,mp[1][id],i-1,x,y,2,rt);mp[1].erase(id);}else{mp[1][id]=i; }}}for(map<int,int>::iterator it=mp[0].begin();it!=mp[0].end();it++){x=it->first/(n+1);y=it->first%(n+1);modify(1,m,it->second,m,x,y,0,rt);modify(1,m,it->second,m,x,y,2,rt);}for(map<int,int>::iterator it=mp[1].begin();it!=mp[1].end();it++){x=it->first/(n+1);y=it->first%(n+1);modify(1,m,it->second,m,x,y,1,rt);modify(1,m,it->second,m,x,y,2,rt);}dfs(1,m,0,rt);dfs(1,m,1,rt);dfs(1,m,2,rt);for(int i=1;i<=m;i++){cout<<ans[0][i]-ans[2][i]<<'\n';} return 0;
}