暑假集训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();
}

魔卡少女樱

[ABC276G] Count Sequences

发现只利用\(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();
}

声之形

不会了

posted @ 2024-08-20 19:27  CuFeO4  阅读(8)  评论(0编辑  收藏  举报