暑假集训CSP提高模拟25
赛时rank 5,T1 100,T2 85,T3 50,T4 5
T2 Tarjan意外挂了,在Tarjan里判割边会挂?
T3 \(O(nm^2)\)暴力能拿50?特判样例能拿60?
可持久化线段树
没啥好说的,主席树板子。
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e5 + 10,mod = 998244353;
int a[N],n,m;
class ChairMan_Tree{
private:
struct segment_tree{
int ls,rs;
ll val,lazy;
#define ls(k) tree[k].ls
#define rs(k) tree[k].rs
#define val(k) tree[k].val
#define lazy(k) tree[k].lazy
}tree[N*50];
int cnt;
inline void pushup(int k){val(k) = (val(ls(k)) + val(rs(k)))%mod;}
public:
int rt[N];
void build(int &k,int l,int r){
k = ++cnt;
if(l == r) return val(k) = a[l],void();
int mid = (l + r) >> 1;
build(ls(k),l,mid);build(rs(k),mid+1,r);
pushup(k);
}
void update(int pre,int &now,int l,int r,int L,int R,int val){
now = ++cnt;
tree[now] = tree[pre];
val(now) = (val(now) + 1ll*(min(r,R) - max(L,l)+1)*val%mod)%mod;
if(L <= l && r <= R)
return lazy(now) = (lazy(now) + val)%mod,void();
int mid = (l + r) >> 1;
if(L <= mid) update(ls(pre),ls(now),l,mid,L,R,val);
if(R > mid) update(rs(pre),rs(now),mid+1,r,L,R,val);
}
int query(int k,int l,int r,int L,int R){
if(!k) return 0;
if(L <= l && r <= R) return val(k);
int mid = (l + r) >> 1,res = 1ll * (min(R,r) - max(L,l) + 1) * lazy(k) % mod;
if(L <= mid) res = (res + query(ls(k),l,mid,L,R))%mod;
if(R > mid) res = (res + query(rs(k),mid+1,r,L,R))%mod;
return res;
}
}T;
inline void solve(){
cin>>n>>m;
for(int i = 1;i <= n; ++i) cin>>a[i];
T.build(T.rt[0],1,n);
int op,l,r,x,tot = 0;
while(m--){
cin>>op;
if(op == 1){
cin>>l>>r>>x;
tot++;
T.rt[tot] = 0;
T.update(T.rt[tot-1],T.rt[tot],1,n,l,r,x);
}
if(op == 2){
cin>>l>>r;
cout<<T.query(T.rt[tot],1,n,l,r)<<'\n';
}
if(op == 3){
cin>>x;
tot -= x;
}
}
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
solve();
}
但是可以直接用线段树暴力撤销,区间加减求和即可。
Little Busters !
考虑先将所有为\(Lun\)的边建图,然后Tarjan缩点,将缩完点后的树边删去。
然后再考虑将\(Qie\)的边加入,用并查集维护联通性,如果一个\(Qie\)边所连得两点已经联通,那么就删去,反之就加上。
最后再判图是否联通即可
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e5 + 10;
struct EDGE{int to,next;}edge[N<<2];
int head[N],cnt = 1;
inline void add(int u,int v){
edge[++cnt] = {v,head[u]};
head[u] = cnt;
}
int dfn[N],low[N],tot,g[N],num;
int sta[N],top;
vector<int> dcc[N];
bitset<N> vis;
int u[N<<1],v[N<<1],n,m;
bitset<N<<1> del;
string w[N<<1];
void Tarjan(int x,int f){
sta[++top] = x;
dfn[x] = low[x] = ++num;
vis[x] = true;
for(int i = head[x]; i;i = edge[i].next){
int y = edge[i].to;
if(!dfn[y]){
Tarjan(y,i);
low[x] = min(low[x],low[y]);
}
else if(i != (f^1)) low[x] = min(low[x],dfn[y]);
}
if(dfn[x] == low[x]){
g[x] = ++tot;
vis[x] = false;
dcc[tot].emplace_back(x);
while(sta[top] != x){
vis[sta[top]] = false;
g[sta[top]] = tot;
dcc[tot].emplace_back(sta[top]);
top--;
}
top--;
}
}
int fa[N];
int get_fa(int x){return x == fa[x]?x:fa[x] = get_fa(fa[x]);}
inline void solve(){
cin>>n>>m;
for(int i = 1;i <= n; ++i) fa[i] = i;
vector<int> q;
for(int i = 1;i <= m; ++i){
cin>>u[i]>>v[i]>>w[i];
if(w[i][0] == 'L') add(u[i],v[i]),add(v[i],u[i]);
else q.push_back(i);
}
for(int i = 1;i <= n; ++i){if(!dfn[i]) Tarjan(i,0);}
for(int now = 1;now <= tot; ++now){
for(int i = 1;i < dcc[now].size(); ++i)
fa[dcc[now][i]] = dcc[now][0];
}
for(int i = 1;i <= m; ++i){
if(w[i][0] != 'L') continue;
int fu = get_fa(u[i]),fv = get_fa(v[i]);
if(fu != fv) del[i] = true;
}
for(auto i : q){
int fu = get_fa(u[i]),fv = get_fa(v[i]);
if(fu == fv){
del[i] = true;
continue;
}
fa[fu] = fv;
}
int tot = 0;
for(int i = 1;i <= n; ++i) if(fa[i] == i) tot++;
if(tot > 1) return cout<<"NO\n",void();
vector<int> ans;
for(int i = 1;i <= m; ++i) if(!del[i]) ans.push_back(i);
cout<<"YES\n";
cout<<ans.size()<<'\n';
for(auto i : ans) cout<<u[i]<<' '<<v[i]<<'\n';
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
solve();
}
魔卡少女樱
发现只利用\(a_i \not\equiv a_{i+1}\pmod 3\)的性质难以处理,那么考虑将其差分
设其差分数组为\(b\),那么有\(b_1=1,b_i=a_i-a_{i-1}\),易知\(\forall i\in [2,n],b_i\not\equiv 0\pmod 3\)
可以先对\(b_i\)对\(3\)取模,所以\(\forall i\in[2,n],b_i\in\{1,2\}, b_1\in\{1,2,3\}\)
由于\(b_i\in\{1,2\}\),可以先钦定有\(j\)个\(b_i=2\),方案数先乘一个\(C_{n-1}^j\),然后枚举\(b_{1\sim n}\)有\(cnt\)个3,就是\(cnt=\left\lfloor\frac{m-j-n+1}{2}\right\rfloor\),考虑插板法。
总可能数为
\[\sum_{k=0}^{n-1}C_{n-1}^k\sum_{j=0}^{cnt}C_{n+j}^j
\]
点此查看代码
#include<bits/stdc++.h>
#include<bits/extc++.h>
// using namespace __gnu_pbds;
// using namespace __gnu_cxx;
using namespace std;
#define infile(x) freopen(x,"r",stdin)
#define outfile(x) freopen(x,"w",stdout)
#define errfile(x) freopen(x,"w",stderr)
#ifdef LOCAL
FILE *InFile = infile("in.in"),*OutFile = outfile("out.out");
// FILE *ErrFile=errfile("err.err");
#else
FILE *Infile = stdin,*OutFile = stdout;
//FILE *ErrFile = stderr;
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int mod = 998244353,N = 2e7 + 10;
int n,m,fac[N],inv[N],sum[N];
inline int power(int a,int b,int mod){
int res = 1;
for(; b;b >>= 1,a = 1ll * a * a % mod)
if(b & 1) res = 1ll * res * a % mod;
return res;
}
inline int C(int n,int m){
if(m>n) return 0;
return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
inline void solve(){
cin>>n>>m;
fac[0] = 1;
for(int i = 1;i <= 20000000; ++i) fac[i] = 1ll * fac[i - 1] * i % mod;
inv[20000000] = power(fac[20000000],mod-2,mod);
for(int i = 20000000-1;i >= 0; --i) inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
sum[0] = 1;
for(int i = 1;i < m; ++i) sum[i] = (sum[i-1] + C(i+n-1,n-1))%mod;
int ans = 0;
for(int i = 0;i < 3; ++i)
for(int j = 0;j < n && j + n - 1 + i <= m; ++j)
ans = (ans + 1ll * C(n-1,j)*sum[(m-j-i-n+1)/3]%mod)%mod;
cout<<ans;
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cout.tie(nullptr)->sync_with_stdio(false);
solve();
}
声之形
不会了
__________________________________________________________________________________________
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18370117