Loading

Codeforces Round 1077 (Div. 1)

我是路边,不知为何粉兔这场爆成和我坐一桌了

Codeforces Round 1077 (Div. 1)

A,B

A 二分。

B 调整+枚举。

C

dsu on tree 都不会了😅😅😅

贪心建一个最短路树然后考虑点对 \(x,y\) 的贡献,式子很容易列,额外的是对于相同深度的点贡献要计算两次。

额外计算相同深度的点的贡献可以按照不同的深度个数 dsu on tree。

树上计算相同深度的所有点对贡献的这种问题,按深度 dsu on tree 复杂度是对的。证明不会😭

但是 y1s1,这个 trick 很容易识别到吧。那我在干什么呢?🙃

复杂度 \(O(nlog^2n)\)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define pll pair<ll,ll>
#define fi first
#define se second
#define lowbit(i) (i&(-i))
const int N = 5e5+10;
ll n,m,ans,to[N],dep[N],siz[N],p[N];
vector<int> e[N];
void dfs(int u){
    siz[u] = 1;
    for(int v:e[u]){
        dep[v] = dep[u]+1;
        dfs(v);
        siz[u] += siz[v];
    }
}
void calc(int u){
    ll pre = 1;
    for(int v:e[u]){
        calc(v);
        ans -= pre*siz[v]*dep[u];
        pre += siz[v];
    }
}
map<ll,ll> ex_calc(int u){
    map<ll,ll> cnt;
    cnt[dep[u]] = 1;
    for(int v:e[u]){
        map<ll,ll> tmp = ex_calc(v);
        if(tmp.size()>cnt.size()) swap(tmp,cnt);
        for(auto x:tmp){
            ans += (x.fi-dep[u])*x.se*cnt[x.fi];
            cnt[x.fi] += x.se;
        }
    }
    return cnt;
}
void solve(){
    cin >> n >> m;
    for(int i=1;i<=n;i++) e[i].clear();
    for(int i=1;i<n;i++) to[i] = i+1;
    for(int i=1;i<=m;i++){
        ll u,v;
        cin >> u >> v;
        to[u] = max(to[u],v);
    }
    for(int i=1;i<n;i++) e[to[i]].pb(i);
    dep[n] = 0;
    dfs(n);
    for(int i=1;i<=n;i++) p[i] = i;
    sort(p+1,p+1+n,[&](int x,int y){
        return dep[x]>dep[y];
    });
    ans = 0;
    for(int i=1;i<=n;i++){
        ans += dep[p[i]]*(i-1);
    }
    calc(n);
    ex_calc(n);
    cout << ans << '\n';
}

int main(){
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    int T = 1;
    cin >> T;
    while(T--) solve();
    return 0;
}

D

我觉得挺好的题。

不会,看 jiangly的视频 学的。

jiangly 通过打表就把结论看出来了,不愧是蒋老师,吓哭了。

想了想这个结论如果要推该怎么推,我感觉是这样的:

我们按照 \(1\) 划分若干段,以 \(0\) 开头的话,序列大概是长这样的 \(x,2x,3x...,ax\),然后遇到了一个 \(1\),后续就会变成 \(y-ax,y-(a-1)x,....\)

最终答案可以表示成 \(ax+by\) 的形式,考虑对于固定的序列 \(s\),尝试找到系数 \(a,b\) 一种容易处理的计算方式。

观察到如果遇到了一个 \(1\)\(y\) 就会一直产生贡献,直到遇到下一个 \(1\) 停止。这样的规律与异或前缀和的计算是类似的。

相当于对于 \(s\),当前位置的异或前缀和为 \(1\) 时,\(y\) 有贡献;否则就没有贡献。所以 \(y\) 的贡献系数就是 \(s\) 做一遍前缀和后 \(1\) 的个数,记为 \(s_y\)

然后分析 \(x\) 的贡献系数,手玩一下这种情况 \(0...010...010...0\),会发现关于 \(x\) 的贡献序列是这个样子的:

\(x,2x,3x,...,bx...,ax,-ax,-(a-1)x,...,-bx,bx,(b+1)x,(b+2)x,....\)

可以看到,每次遇到一个 \(1\),系数就取反一次。于是放在前缀和上面分析。

对应的前缀和情况就是 \(0...01...10...0\),很容易观察到 \(1\) 的部分的系数会将前面 \(0\) 部分的系数的一段后缀抵消掉,而在后面的 \(0\) 部分又会正好从抵消掉的值那里开始重新增加。

假设我们一开始是全 \(0\),贡献就是 \(\frac{n(n+1)}{2} x\),而前缀和中每出现一次 \(1\),就会让这个 \(n\) 减去 \(2\),因为它占一个位置的同时还会抵消掉前面的一个位置。

所以 \(x\) 的贡献系数 \(s_x = \frac{(n-2s_y)(n-2s_y+1)}{2}\)

由此可以看出,贡献仅由前缀和中 \(1\) 的个数决定,所以至多 \(n+1\) 种。

因此我们只需要找出所有可能的 \(s_y\) 即可。

本题 \(10^5~~4s\),可以用 bitset 维护当前前缀可能的 \(1\) 的个数,顺次转移即可。

复杂度 \(O(\frac{n^2}{w})\)

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
const ll mod = 998244353;
const int N = 1e5+10;
ll n,x,y,ans;
char s[N];
bitset<N> state[2],tmp[2];
void solve(){
    cin >> n >> x >> y;
    for(int i=1;i<=n;i++) cin >> s[i];
    ans = 0;
    state[0].reset(),state[0].set(0);
    state[1].reset(),tmp[0].reset(),tmp[1].reset();
    for(int i=1;i<=n;i++){
        if(s[i] != '?'){
            if(s[i] == '1'){
                tmp[0] = state[0];
                state[0] = state[1];
                state[1] = (tmp[0]<<1);
            }else{
                state[1] = (state[1]<<1);
            }
        }else{
            tmp[0] = state[0],tmp[1] = state[1];
            state[0] = tmp[0]|tmp[1];
            state[1] = (tmp[0]<<1)|(tmp[1]<<1);
        }
    }
    map<ll,int> vis;
    for(int i=0;i<=n;i++) {
        if(state[0][i] == 0 && state[1][i] == 0) continue;
        ll val = y*i+x*((n-2*i)*(n-2*i+1)/2);
        if(vis[val]) continue;
        vis[val] = 1,val %= mod;
        ans += val;
        if(ans >= mod) ans -= mod;
    }
    cout << ans << '\n';
}
int main(){
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);
    int T;cin >> T;
    while(T--) solve();
    return 0;
}
posted @ 2026-01-30 23:13  Regules  阅读(30)  评论(0)    收藏  举报