AtCoder Beginner Contest 378 题解

AtCoder Beginner Contest 378

Rated: \(760 \to 770\)
场切:ABCD
赛后:EF
不会:G

  • A - Pairing

    简单模拟。

  • B - Garbage Collection

    找到一个大于等于 \(d\) 的最小值,满足模 $q = r $。
    简单分讨。

  • C - Repeating

    简单模拟。

  • D - Count Simple Paths

    纯DFS。
    枚举每个起点,暴力搜索统计答案。

  • E - Mod Sigma Problem

    假设 \(S_i = (A_1+A_2+\dots+A_i) \mathbin{\mathrm{mod}} M,S_0 = 0\),那么

    \[ \sum_{1 \leq l \leq r \leq N} \left( \left(\sum_{l \leq i \leq r} A_i\right) \mathbin{\mathrm{mod}} M \right) = \sum_{1 \leq l \leq r \leq N} (S_r - S_{l-1}) \mathbin{\mathrm{mod}} M, \]

    由于 \(0 \leq S_{l-1},S_r \lt M\) ,所以

    \[ (S_r - S_{l-1}) \mathbin{\mathrm{mod}} M = S_r - S_{l-1} + \begin{cases} 0 & (S_{l-1} \leq S_r) \\ M & (S_{l-1} \gt S_r)\end{cases} \]

    不再涉及 \(\mathrm{mod}\)

    让 $X_r = $ ( \(l=1,2,\dots,r\)\(S_{l-1} \gt S_r\) 的个数),那么

    \[ \sum_{r=1}^N \sum_{l=1}^r (S_r - S_{l-1}) \mathbin{\mathrm{mod}} M = \sum_{r=1}^N \left( S_r \times r - \sum_{l=1}^r S_{l-1} + M \times X_r \right). \]

    \(X_r\) 可以用值域树状数组值域线段树来计算。

    \(B_x\) 定义为 \(S_{l-1}=x\) 的个数,
    对每个 \(r=0,1,\dots,N\) 执行以下操作:

    • \(X_r = B_{S_r + 1} + B_{S_r + 2} + \dots B_{M-1}\)
    • \(B_{S_r} + 1\)

    细节:当 \(S_i = 0\) 时,执行 add(S[i],1) 时,lowbit(S[i]) 会一直为 \(0\),会死循环。所以给每个 \(S_i + 1\) 维护。

    点击查看代码
    #include <bits/stdc++.h>
    using namespace std;
    const int N = 200005;
    long long a[N],tr[N];
    long long n,m;
    int lowbit(int x){
        return x & -x;
    }
    void add(int x,int k){
        for (int i = x; i <= m;i+=lowbit(i))
            tr[i] += k;
    }
    int query(int x){
        long long sum = 0;
        for (int i = x; i;i-=lowbit(i))
            sum += tr[i];
        return sum;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0),cout.tie(0);
        cin >> n >> m;
        for (int i = 1; i <= n;i++)
            cin >> a[i], a[i] = (a[i]+a[i - 1])%m;
        long long tmp = 0,ans=0;
        for (int i = 1; i <= n;i++){
            ans += a[i] * i;
            ans -= tmp;
            ans += (query(m) - query(a[i]+1))*m;
            add(a[i]+1, 1);
            tmp += a[i];
        }
        cout << ans << endl;
        return 0;
    }
    
  • F - Add One Edge 2

    计算满足以下条件的顶点对 \((u, v)\) (其中 \(u \lt v\) )的个数:

    • \(u\)\(v\) 的度数都是 \(2\)
    • \(u\)\(v\) 的简单路径上的所有顶点(不包括 \(u\)\(v\) 本身)的度数都是 \(3\)

    并查集维护,给每个顶点度数都为 \(3\) 的边合并。
    \(c_i\) 表示第 \(i\) 个连通块中,与联通块中的点有连边的,且度数为 \(2\) 的点的数量。

    答案就是 \(\displaystyle\sum_{i=1}^{} \frac{c_i(c_i - 1)}{2}\)

    点击查看代码
    #include <bits/stdc++.h>
    using namespace std;  
    
    const int N = 200005;
    int n;
    int u[N], v[N], deg[N], fa[N];
    int c2[N];
    
    int find(int x) {
    	return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    
    void merge(int x, int y) {
    	int fx = find(x),fy = find(y);
    	fa[fx] = fy;
    }
    
    vector<vector<int>> f() {
    	unordered_map<int, vector<int>> t;
    	for (int i = 0; i < n; ++i) {
    		int rt = find(i);
    		t[rt].push_back(i);
    	}
    	vector<vector<int>> ans;
    	for (const auto& tmp : t) {
    		ans.push_back(tmp.second);
    	}
    	return ans;
    }
    
    signed main() {
    
    	cin >> n;
    	for (int i = 1; i <= n - 1; i++) {
    		cin >> u[i] >> v[i];
    		u[i]--;v[i]--;
    		deg[u[i]]++;deg[v[i]]++;
    	}
    
    	for (int i = 0; i < n; ++i)
    		fa[i] = i;
    
    	for (int i = 1; i <= n - 1; ++i) {
    		if (deg[u[i]] == 3 && deg[v[i]] == 3)
    			merge(u[i], v[i]);
    		else if (deg[u[i]] == 3 && deg[v[i]] == 2) 
    			c2[u[i]]++;
    		else if (deg[u[i]] == 2 && deg[v[i]] == 3) 
    			c2[v[i]]++;
    	}
    
    	long long ans = 0;
    	for (const auto& g : f()) {
    		long long cnt = 0;
    		for (int v : g)
    			cnt += c2[v];
    		ans += cnt * (cnt - 1) / 2;
    	}
    	cout << ans << endl;
    	return 0;
    }
    
  • G - Everlasting LIDS

    官方题解

posted @ 2024-11-02 22:34  Star_F  阅读(137)  评论(0)    收藏  举报