Codeforces Edu80

Codeforces Edu80

A

题面

思路

显然,当 \(x\)\(sqrt(d)\) 附近时,\(x + \lceil\frac{d}{x+1}\rceil\) 较小,枚举一下即可。

Code

#include <bits/stdc++.h>
 
using namespace std;
 
const int maxn = 1e5+10;
 
typedef long long ll;
ll _, n, d;
 
int main() {
    for (scanf("%lld", &_); _; _--) {
        scanf("%lld%lld", &n, &d);
        if(d <= n) {
            puts("YES");
            continue;
        }
        ll sqt = sqrt(d)-1;
        bool fg = false;
        for (ll i = sqt; i <= 2*sqt; ++i) {
            if(i + (d+i)/(i+1) <= n) {
                fg = 1;
                break;
            }
        }
        puts(fg? "YES": "NO");
    }
 
    return 0;
}

B

题面

思路

显然,当且仅当 \(b = 9,99,999,9999 \dots\) 时满足条件。

Code

#include <bits/stdc++.h>
 
using namespace std;
 
const int maxn = 1e5+10;
 
typedef long long ll;
ll _, A, B;
 
int main() {
    for (scanf("%lld", &_); _; _--) {
        scanf("%lld%lld", &A, &B);
        if(B%10==9) ++B;
        int res = 0;
        while(B) {
            ++res;
            B /= 10;
        }
        printf("%lld\n", A*(res-1));
    }
 
    return 0;
}

C

题面

思路:

两个数组可拼成一个:

\(a_1, a_2, \dots, a_m, b_m, b_{m-1}, \dots, b_1\)

该问题可用隔板法解释: \(2m\) 个位置与 \(n\) 个数可用 \(n-1\) 个隔板分隔。

最终答案:\(\binom{n+2m-1}{n-1}\)

Code

#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
const int maxn = 1e5+10;
const int mod = 1e9 + 7;
ll fac[maxn], inv[maxn];
ll _, A, B;
 
ll ksm(ll a, ll n) {
    ll res = 1;
    while(n) {
        if(n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}
void init() {
    fac[0] = 1;
    for (int i = 1; i < maxn; ++i) fac[i] = fac[i-1] * i % mod;
    inv[maxn-1] = ksm(fac[maxn-1], mod-2);
    for (int i = maxn - 2; i >= 0; --i) inv[i] = inv[i+1]*(i+1)%mod;
}
ll C(int n, int m) {
    return fac[n] * inv[m] % mod * inv[n-m] % mod;
}
 
int main() {
    init();
    int n, m;
    scanf("%d%d", &n, &m);
    printf("%lld\n", C(n + 2 * m - 1,  n-1));
    return 0;
}

D

题面

思路

二分最值。

假设临界值为 \(x\),大于等于 \(x\) 的设为 1, 小于 \(x\) 的设为 0。

则对于每个数组,可转为长度为m的01串,我们需要保证 \(bit[i] | bit[j] == 2^{m}- 1\) 即可

将每一个 \(bit[i]\) 插入字典树中。

对于数组 \(i\) ,查询是否有能满足条件的 \(j\) 即可。

Code

#include <bits/stdc++.h>
 
using namespace std;
 
const int maxn = 3e5+10;
const int inf = 0x3f3f3f3f;
 
int n, m, a[maxn][10];
int bit[maxn][10];
int trie[maxn*10][2];
int ed[maxn*10];
int pn = 0;
 
void insertTree(int x) {
    int p = 0;
    for (int c, i = 1; i <= m; ++i) {
        c = bit[x][i];
        if(!trie[p][c]) trie[p][c] = ++pn;
        p = trie[p][c];
    }
    ed[p] = x;
}
int inTree(int x) {
    int p = 0;
    for (int c, i = 1; i <= m; ++i) {
        c = 1 - bit[x][i];
        if(!trie[p][c]) {
            if(!c && trie[p][!c]) c = 1-c;
            else return false;
        }
        p = trie[p][c];
    }
    return ed[p];
}
 
int check(int x) {
    memset(trie, 0, sizeof(trie));
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j)
            bit[i][j] = (a[i][j] >= x);
        insertTree(i);
    }
    for (int i = 1; i <= n; ++i) {
        if(inTree(i))
            return i;
    }
    return 0;
}
 
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j)
            scanf("%d", &a[i][j]);
    }
 
    int l = 0, r = inf;
    while(l <= r) {
        int mid = l + r >> 1;
        if(check(mid)) l = mid + 1;
        else r = mid - 1;
    }
    int ans = check(r);
    printf("%d %d\n", ans, inTree(ans));
    return 0;
}

E

题面

思路

对于一个数,若未曾主动改变过,则最小值为初始位置,否则为 1。

对于其最大值,影响其位置的只有其左边有多少个数。因此,我们只需要用树状数组模拟其改变过程即可,只需在其主动移动或m次操作之后时,更新其最大值位置即可。

Code

#include <bits/stdc++.h>
 
using namespace std;
 
const int maxn =6e5+10;
 
int tree[maxn], n, m;
inline int lowbit(int x) { return x&-x; }
inline void modify(int x, int val) { for (int i = x; i < maxn; i += lowbit(i)) tree[i] += val; }
inline int query(int x) {
    int res = 0;
    for (int i = x; i; i -= lowbit(i)) res += tree[i];
    return res;
}
 
int l[maxn], r[maxn], pos[maxn];
int a[maxn];
 
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; ++i) scanf("%d", a+i);
    for (int i = 1; i <= n; ++i) {
        l[i] = r[i] = i;
        pos[i] = m + i;
        modify(pos[i], 1);
    }
 
    for (int x, i = 1; i <= m; ++i) {
        x = a[i];
        l[x] = 1;
        r[x] = max(r[x], query(pos[x]));
        modify(pos[x], -1);
        pos[x] = m - i + 1;
        modify(pos[x], 1);
    }
 
    for (int i = 1; i <= n; ++i) r[i] = max(r[i], query(pos[i]));
    for (int i = 1; i <= n; ++i) printf("%d %d\n", l[i], r[i]);
 
    return 0;
}

F

留坑,待补。

posted @ 2020-01-18 15:09  Acerkoo  阅读(128)  评论(0编辑  收藏  举报