yuwj  

写在前面

已经,无所谓了

C 题没看懂,不写了,F 只有一个过了,也不想写了

A

相当于就是填数字,总共的数字个数是 加号个数 + 1

然后发现要用高精度,完了

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using ll = long long;

struct BigInt{
	vector<int> d;
	
	BigInt(){}
	BigInt(ll x){*this = x;}
    BigInt(string &s){ *this = s; }
	
    BigInt& operator=(const string &s){
        d.clear();
        for (int i = (int)s.size() - 1; i >= 0; --i) d.push_back(s[i] - '0');
        trim();
        return *this;
    }

    BigInt& operator=(ll x){
		d.clear();
		if(x==0){d.push_back(0); return *this;}
		while(x) {d.push_back(x%10), x/=10;}
		return *this;
	}

	void trim(){
		while(d.size()>1 && d.back() == 0) d.pop_back();
	}

	bool isZero() const {return d.size() == 1 && d[0] == 0;} 

	static int cmp(BigInt A, BigInt B){
        A.trim(); B.trim();
        if(A.d.size() != B.d.size()) return A.d.size() < B.d.size() ? -1 : 1;
        int n = A.d.size(), m = B.d.size();
		for(int i = min(n,m)-1; i >= 0; --i){
            if(A.d[i] != B.d[i]) return A.d[i] < B.d[i] ? -1 : 1;
        }
        return 0;
    }
};

BigInt operator*(const BigInt A, const BigInt B){
	if(A.isZero() || B.isZero()) return BigInt(0);

	BigInt res;
	res.d.assign(A.d.size() + B.d.size(),0);
	for(int i = 0; i<A.d.size(); ++i){
		int j=0, cur = 0, x = A.d[i];
		for(;j<B.d.size();++j){
			ll now = res.d[i+j] + x*B.d[j] + cur;
			res.d[i+j] = now%10, cur = now/10;
		}
		while(cur){
			ll now = res.d[i+j] + cur;
			res.d[i+j] = now%10;
			cur = now/10, ++j;
		}
	}
	res.trim();
	return res;
}

BigInt operator+(const BigInt &A, const BigInt &B){
    BigInt res;
    int n = A.d.size(), m = B.d.size();
    int L = max(n, m), now = 0;
    res.d.resize(L);
    for (int i = 0; i < L; ++i){
        int x = now;
        if(i<n) x += A.d[i];
        if(i<m) x += B.d[i];
        res.d[i] = x % 10;
        now = x / 10;
    }
    if (now) res.d.push_back(now);
    return res;
}

void solve(){
    string s; cin >> s;
    int num = 1; 
    vector<int> cnt(10);
    for(auto ch : s){
        if(ch == '+') num++;
        else cnt[ch - '0']++;
    }

    vector<string> a(num+1);
    int idx = 1;
    for(int i = 1; i <= 9; ++i)if(cnt[i]){
        for(int j = 1; j <= cnt[i]; ++j){
            a[idx].push_back(char(i + '0'));
            idx = (idx + 1) % (num+1);
            if(idx == 0) idx = 1;
        }
    }

    // cerr << num << '\n';

    // 高精度,得要
    BigInt ans = 0;
    for(int i = 1; i <= num; ++i){
        if(a[i].size())ans = ans + BigInt(a[i]);
        // cerr << a[i] << '\n';
    }

    auto vec = ans.d;
    for(int i = vec.size() - 1; i >= 0; --i) cout << vec[i];
}

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

B

就是走距离为偶数的路径数量

定义: f[u]:以 u 为根节点的子树中奇数层节点数量,g[u]:以 u 为根节点的子树中偶数层节点数量

然后 dp[u]:表示以 u 为根节点的子树中偶数长度距离的节点对数,然后答案就对所有子树的方案求和完了

发现每个子树的贡献其实是所有点与兄弟节点的组合,

最后,注意是有序对

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;

constexpr int Maxn = 1e6+10;
vector<int> G[Maxn];

// 求一定能胜利的方案数
// 就是路径长度为偶数的路径数量 -> 点的层数奇偶分类,然后对子树 dp 计数完了
void solve(){
    int n;
    cin >> n;

    for(int i = 2; i <= n; ++i){
        int p; cin >> p;
        G[p].push_back(i), G[i].push_back(p);
    }

    vector<i64> f(n+1), g(n+1), dp(n+1);
    
    function<void(int,int)> dfs = [&](int u,int fa) -> void{
        vector<int> sons;
        f[u] = 1;
        int odd = 0, even = 0;
        for(auto v : G[u]){
            if(v == fa) continue;
            dfs(v,u);
            sons.push_back(v);
            f[u] += g[v], g[u] += f[v];
            odd += f[v], even += g[v];
        }

        for(auto v : sons){
            dp[u] += 1ll*f[v]*(odd - f[v]) + 1ll*g[v]*(even - g[v]);
        }

        dp[u] += (f[u]-1) * 2;
    };

    dfs(1,0);

    i64 ans = 0;

    for(int i = 1; i <= n; ++i) ans += dp[i];
    
    cout << ans << '\n';
}

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

D

就是询问的颜色区间内左右端点的组合方案数的和

考虑单点修改区间查询的线段树即可解决这个问题

template <class Info>
struct SegmentTree {
	struct Node {
		int l, r;
		Info info;
	};

	std::vector<Node> tr;

	SegmentTree() {};
	SegmentTree(int n) {
		init(n);
	}

	SegmentTree(std::vector<Info> & info) {
		init(info);
	}

	void init(int n) {
		tr.assign(n << 2, {});
		build(0, n - 1);
	}

	void init(std::vector<Info> & info) {
		int n = info.size();
		tr.assign(n << 2, {});
		std::function<void(int, int, int)> build = [&](int l, int r, int u) -> void {
			tr[u] = {l, r, {}};
			if (l == r) {
				tr[u].info = info[l];
				return;
			}

			int mid = l + r >> 1;
			build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);
			pushup(u);
		};

		build(0, n - 1, 1);
	}

	void pushup(int u) {
		tr[u].info = tr[u << 1].info + tr[u << 1 | 1].info;
	}

	void build(int l, int r, int u = 1) {
		tr[u] = {l, r, {}};
		if (l == r) {
			return;
		}

		int mid = l + r >> 1;
		build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);
		pushup(u);
	}

	void modify(int p, const Info & info, bool set = false) {
		int u = 1;
		while (tr[u].l != tr[u].r) {
			int mid = tr[u].l + tr[u].r >> 1;
			if (p <= mid) {
				u = u << 1;
			} else {
				u = u << 1 | 1;
			}
		}

		if (set) {
			tr[u].info = info;
		} else {
			tr[u].info = tr[u].info + info;
		}

		u >>= 1;
		while (u) {
			pushup(u);
			u >>= 1;
		}
	}

	Info query(int l, int r, int u = 1) {
		if (l <= tr[u].l && tr[u].r <= r) {
			return tr[u].info;
		}

		int mid = tr[u].l + tr[u].r >> 1;
		if (r <= mid) {
			return query(l, r, u << 1);
		} else if (l > mid) {
			return query(l, r, u << 1 | 1);
		}

		return query(l, r, u << 1) + query(l, r, u << 1 | 1);
	}
};

struct Info{
    int sum;
};

Info operator+(const Info &l, const Info &r){
    Info res;
    res.sum = l.sum + r.sum;
    return res;
}

// 其实是颜色区间内不包含 i 位置颜色的三元组对数的和的数量
const int N = 5e5 + 10;
int cntl[N], cntr[N];
void solve(){
    int n;
    cin >> n;
    vector<T> num(n);

    for(auto &[col, l, r] : num) cin >> col >> l >> r, cntr[col]++;
    
    SegmentTree<Info> tr(N + 1);

    for(auto [col, l, r] : num){
        cntr[col]--;
        i64 x = 1ll * cntl[col] * cntr[col];
        
        tr.modify(col, {x}, 1);
        cout << tr.query(l,r).sum << ' ';
        
        cntl[col]++;
        x = 1ll * cntl[col] * cntr[col];
        tr.modify(col, {x}, 1);
    }
}

E

显然是 z = 1 类和 z = 0 类进行配对,

先排序 x,然后找 y,每次都找到最大的能够满足的 y 配对就能贪到最大匹配数量

可以用 multiset 完成这个事情

#include <bits/stdc++.h>
using namespace std;

using i64 = long long;
using T = tuple<int,int,int>;

void solve(){
    int n;
    cin >> n;
    vector<T> point(n);

    for(auto &[x,y,z] : point) cin >> x >> y >> z;
    
    sort(point.begin(), point.end());

    multiset<int> mst;
    
    int ans = 0;

    for(auto [x,y,z] : point){
        if(z == 1){
            auto it = mst.lower_bound(y);
            if(it != mst.begin()){
                ++ans;
                --it; mst.erase(it);
            }
        }else{
            mst.insert(y);
        }
    }

    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(); cin.tie(0); cout.tie(0);
    int t = 1;
    // cin >> t;
    while(t--){
        solve();
    }
    return 0;
}
posted on 2025-11-05 22:26  xiaowang524  阅读(0)  评论(0)    收藏  举报