2021 ICPC 昆明(22-4-17) C L E | 第46届ICPC亚洲区域赛(昆明)

ICPC 2021 昆明

传送门

补题计划 CLE,

C - Cup of Water

prob : 在0-V内随机取数灌满1升水的期望操作次数

idea1:

首先将题给的“在0-V内随机取数灌满1升水”改为“在0-1内随机取数灌满 1 V \frac{1}{V} V1升水”

这样方程是统一的,否则在V>1和<1的情况下形式不同

def f ( x ) : = f(x) := f(x)= 已有x升水的情况下,灌满1升水的期望步数

f ( x ) = 1 + ∫ m a x ( 0 , x − 1 ) x f ( x − t ) d t f(x) = 1 + \int_{max(0,x-1)}^{x}f(x - t)\mathrm{d}t f(x)=1+max(0,x1)xf(xt)dt

分成若干小段然后求体积和

btw >1的值是 e x p ( 1 x ) exp(\frac{1}{x}) exp(x1),不会证但感觉非常优美(

有轻微调参

code :

#include <bits/stdc++.h>

using namespace std;

const int N = 7e5;

//typedef long double lb;
double dp[N * 20 + 10], pre[N * 20 + 10];

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

    int T;
    cin >> T;
    for (int i = 1; i < N * 20 + 5; ++i) {
        dp[i] = 1 + (double)(pre[i - 1] - pre[max(i - N, 0)]) / (double)N;
        pre[i] = pre[i - 1] + dp[i];
    }
    while (T--) {
        double V;
        cin >> V;
        cout << fixed << setprecision(10) << dp[(int)(1.0 / V * (N)) + 1] << endl;
    }

    return 0;
}

C题 官方题解做法和高维体积容斥(?)思路待
推荐一下zx宝贝的C题题解

L - Light of Stars

prob. : 二维平面上n个星星,每个星星有k个照的角度区间,(区间不重合,且所有星星的角度是一样的),问每个星星被多少个星星照到

每个角度分开做,做k次

坐标一步步变换成图4的样子,二维偏序计数
(因为统计每个星星被照到几次,将照的角度变成右上角90°的范围,他的左下角(即x<this.x & y <this.y 的范围内的点就是能照到他的点))
在这里插入图片描述

code:

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;
const double PI = acos(-1.0);
const double eps = 1e-9;

//#define double long double

struct node {
    double x, y;
};

struct note {
    double x, y;
    int id;
};

note tmp[N << 2];

node p[N];
int ans[N];
int n;

int tree[N];

int lowbit(int x) {
    return x & (-x);
}

void update(int i, int x) {
    while (i <= n) {
        tree[i] += x;
        i += lowbit(i);
    }
}

int query(int i) {
    int res = 0;
    while (i) {
        res += tree[i];
        i -= lowbit(i);
    }
    return res;
}

note rotate(const note &a, const double &ang) {
    double x = cos(ang) * a.x - sin(ang) * a.y;
    double y = sin(ang) * a.x + cos(ang) * a.y;
    return {x, y, a.id};
}

int cmp(double a, double b) {
    if (abs(a - b) < eps) return 0;
    if (a > b) return 1;
    return -1;
}

void solve(int l, int r) {
    memset(tree, 0, sizeof tree);

    for (int i = 1; i <= n; ++i) {
        tmp[i].x = p[i].x;
        tmp[i].y = p[i].y;
        tmp[i].id = i;
    }

    vector<double> vec;

    for (int i = 1; i <= n; ++i) {
        tmp[i] = rotate(tmp[i], (double) (l + r)* PI / 360.0);
        tmp[i].x = tan((double) (r - l) * PI / 360.0) * tmp[i].x;
        tmp[i] = rotate(tmp[i], (double) 45 * PI / 180.0);
        vec.push_back(tmp[i].y);
    }

    sort(tmp + 1, tmp + n + 1, [&](note a, note b) {
        if (cmp(a.x, b.x) != 0) return a.x < b.x;
        return a.y < b.y;
    });

    sort(vec.begin(), vec.end());
    vec.erase(unique(vec.begin(), vec.end(), [&](double x, double y) {
        return abs(x - y) < eps;
    }), vec.end());

    for (int i = 1; i <= n; ++i) {
        int y = lower_bound(vec.begin(), vec.end(), tmp[i].y + eps) - vec.begin() + 1;
        ans[tmp[i].id] += query(y);
        update(y, 1);
    }

}

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

    int k;
    cin >> n >> k;

    for (int i = 1; i <= n; ++i) {
        cin >> p[i].x >> p[i].y;
    }

    for (int i = 0; i < k; ++i) {
        int l, r;
        cin >> l >> r;
        if (l > r) swap(l, r);
        solve(l, r);
//        for (int j = 1; j <= n; ++j) {
//            cerr << ans[j] << " ";
//        }
//        cerr << endl;
    }

    for (int i = 1; i <= n; ++i) {
        cout << ans[i] << " ";
    }

    return 0;
}

E - Easy String Problem

prob. : 给一个字符串,若干次询问,每次问删去包含 [ L , R ] [L, R] [L,R]区间的子串形成的不同的字符串的数量

idea :

刚开始一直觉得如果有两个区间的字符串是一样的,这个串包含了 O ( l e n 2 ) O(len^2) O(len2)个相同的区间所以贡献是 O ( l e n 2 ) O(len^2) O(len2),然后觉得非常不可做

可他有 O ( l e n ) O(len) O(len) 种长度啊

如果删去 [ l , r ] [l, r] [l,r] 区间的字符串与删去 [ l + k , r + k ] [l + k, r + k] [l+k,r+k] 区间的字符串相等,则对于 i ∈ [ 0 , k ] i \in [0, k] i[0,k] 删去 [ l + i , r + i ] [l + i, r + i] [l+i,r+i] 区间得到的字符串都相等

题目转化成求满足 [ l , r ] ≠ [ l − 1 , r − 1 ] [l,r ] \not =[l - 1, r - 1] [l,r]=[l1,r1]的数量

L × ( n − R + 1 ) − c n t { [ l , r ] = [ l − 1 , r − 1 ] } L\times(n -R+1) - cnt\{[l,r ] =[l - 1, r - 1]\} L×(nR+1)cnt{[l,r]=[l1,r1]}

[ l , r ] = [ l − 1 , r − 1 ] [l,r ] =[l - 1, r - 1] [l,r]=[l1,r1] 又可以转化成求两边相同的字符对数

莫队

code :

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const ll N = 1e5 + 10;


struct node {
    ll l, r;
    ll id;
};

ll len;
ll a[N], cntLeft[N], cntRight[N], ans[N];
node ques[N];
ll n;

ll getNum(ll l) {
    return l / len;
}

void add(ll x, ll &res, ll op) {
    if (op == 1) {
        res -= cntLeft[x];
        cntRight[x]--;
    } else {
        res -= cntRight[x];
        cntLeft[x]--;
    }
}

void del(ll x, ll &res, ll op) {
    if (op == 1) {
        res += cntLeft[x];
        cntRight[x]++;
    } else {
        res += cntRight[x];
        cntLeft[x]++;
    }
}

signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);

    cin >> n;
    for (ll i = 1; i <= n; ++i) {
        cin >> a[i];
        cntRight[a[i]]++;
    }
    ll q;
    cin >> q;
    for (ll i = 1; i <= q; ++i) {
        cin >> ques[i].l >> ques[i].r;
        ques[i].id = i;
    }

    len = sqrt((double) n * n / q);

    sort(ques + 1, ques + q + 1, [&](node a, node b) {
        if (getNum(a.l) != getNum(b.l)) return a.l < b.l;
        return a.r < b.r;
    });

    ll i = 0, j = 0, res = 0;
    for (ll k = 1; k <= q; ++k) {
        ll id = ques[k].id, l = ques[k].l, r = ques[k].r;
        while (j < r) add(a[++j], res, 1);
        while (j > r) del(a[j--], res, 1);
        while (i < l) del(a[i++], res, 0);
        while (i > l) add(a[--i], res, 0);
        ans[id] = l * (n - r + 1) - res;
    }

    for (ll k = 1; k <= q; ++k) cout << ans[k] << endl;

    return 0;
}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值