写在前面
已经,无所谓了
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;
}

浙公网安备 33010602011771号