欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

2020 计蒜之道 线上决赛(C,D,E,F,G)

程序员文章站 2022-03-27 16:05:21
D. 两个多项式的卷积数据范围样例输入复制21 2 33 2 131 1 42 0 -11 1 4样例输出复制3330标准题解:自己就照这个思路写的,不多说,上板子/**/#include #include #include #include #include #include

最近很长时间都很忙,写这篇主要是挂一下代码。

A略

B略

C.攀登山峰

2020 计蒜之道 线上决赛(C,D,E,F,G)

样例输入复制

8 3
1 2 1 4 4 5 3 3 
3 7 5
1 4 3
3 8 6

样例输出复制

4
1
4

 题解:

2020 计蒜之道 线上决赛(C,D,E,F,G)

std:

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const int maxn = 1e5 + 5;

int n, m, cnt, a[maxn], b[maxn], rt[maxn];
int tr[maxn << 5], ls[maxn << 5], rs[maxn << 5];

void build(int &now, int l, int r){
    tr[now = ++cnt] = 0;
    if(l == r) return ;
    int mid = (l + r) >> 1;
    build(ls[now], l, mid);
    build(rs[now], mid + 1, r);
}

void up(int now){
    tr[now] = tr[ls[now]] + tr[rs[now]];
}

void update(int &now, int &old, int l, int r, int w){
    tr[now = ++cnt] = tr[old] + 1;
    ls[now] = ls[old], rs[now] = rs[old];
    if(l == r){
        // tr[now]++;
        return ;
    }
    int mid = (l + r) >> 1;
    if(mid >= w) update(ls[now], ls[old], l, mid, w);
    else update(rs[now], rs[old], mid + 1, r, w);
    // up(now);
}

int query(int now, int old, int l, int r, int num){
    if(l == r) return l;
    int mid = (l + r) >> 1;
    int res = 0;
    if(tr[ls[old]] - tr[ls[now]] > num){
        res = max(res, query(ls[now], ls[old], l, mid, num));
    }
    if(tr[rs[old]] - tr[rs[now]] > num){
        res = max(res, query(rs[now], rs[old], mid + 1, r, num));
    }
    return res;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
    sort(b + 1, b + 1 + n);
    int cnt = unique(b + 1, b + 1 + n) - b - 1;
    build(rt[0], 1, cnt);
    b[0] = -1;
    for (int i = 1; i <= n; i++) update(rt[i], rt[i - 1], 1, cnt, a[i] = lower_bound(b + 1, b + 1 + cnt, a[i]) - b);
    for (int i = 1, l, r, t; i <= m; i++){
        scanf("%d %d %d", &l, &r, &t);
        int len = (r - l + 1) / t;
        printf("%d\n", b[query(rt[l - 1], rt[r], 1, cnt, len)]);
    }

    return 0;
}
/**/

 

D. 两个多项式的卷积

2020 计蒜之道 线上决赛(C,D,E,F,G)

数据范围

样例输入复制

2
1 2 3
3 2 1
3
1 1 4
2 0 -1
1 1 4

样例输出复制

33
30

题解:

2020 计蒜之道 线上决赛(C,D,E,F,G)

 

std:

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const int maxn = 4e4 + 5;
const int mod = 998244353;

int lim = 1, L, G = 3, Gi = 332748118;
int n, m, cnt, a[maxn], A[maxn], b[maxn], c[maxn], rev[maxn << 1], pos[maxn], w[maxn], pre[maxn];

LL poww(LL x, LL num){
    LL res = 1;
    while(num){
        if(num & 1) res = res * x % mod;
        x = x * x % mod;
        num >>= 1;
    }
    return res;
}

void ntt(int *a, int type){
    for (int i = 0; i < lim; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
    static int x, y;
    for (int mid = 1; mid < lim; mid <<= 1){
        int len = mid << 1, wn = poww(type ? G : Gi , (mod - 1) / (mid << 1));
        for (int i = 0; i < lim; i += len){
            for (int j = 0, w = 1; j < mid; j++, w = 1LL * w * wn % mod){
                x = a[i + j], y = 1LL * w * a[i + mid + j] % mod;
                a[i + j] = (x + y) % mod, a[i + mid + j] = (x + mod - y) % mod;
            }
        }
    }
    if(!type){
        LL inv = poww(lim, mod - 2);
        for (int i = 0; i < lim; i++) a[i] = (1LL * inv * a[i] % mod + mod) % mod;
    }
}

void init(){
    while(lim <= n) lim <<= 1, L++;
    for (int i = 0; i < lim; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
}

void doNTT(){
    for (int i = 0; i < lim; i++) A[i] = a[i];
    ntt(A, 1);
    for (int i = 0; i < lim; i++) c[i] = (1LL * A[i] * b[i] % mod + mod) % mod;
    ntt(c, 0);
    for (int i = 1; i < lim; i++) c[i] = (c[i] + c[i - 1]) % mod;
}

LL cal(int x){
    if(x < 0) return 0LL;
    LL sum = c[x];
    for (int i = 1; i <= cnt; i++){
        int r = x - pos[i];
        // printf("===%d %d %d\n", i, r, pre[r]);
        if(r >= 0) sum = (sum + 1LL * w[i] * pre[r] % mod + mod) % mod;
    }
    return sum;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%d", &n);
    for (int i = 0; i <= n; i++) scanf("%d", &a[i]), a[i] = (a[i] % mod + mod) % mod;
    for (int i = 0; i <= n; i++){
        scanf("%d", &b[i]);
        b[i] = (b[i] % mod + mod) % mod;
        if(i) pre[i] = (pre[i - 1] + b[i]) % mod;
        else pre[i] = b[i];
    }
    scanf("%d", &m);
    n <<= 1;
    for (int i = n / 2 + 1; i <= n; i++) pre[i] = pre[i - 1];
    init();
    ntt(b, 1);
    doNTT();
    int mx = sqrt(n * log10(1.0 * n) / log10(2.0)) + 1;
    cnt = 0;
    for (int i = 1, op, l, r; i <= m; i++){
        scanf("%d %d %d", &op, &l, &r);
        if(op == 1){
            printf("%lld\n", (cal(r) - cal(l - 1) + mod) % mod);
        }else{
            pos[++cnt] = l;
            a[l] += (w[cnt] = r);
            a[l] = (a[l] % mod + mod) % mod;
            if(cnt == mx + 1){
                doNTT();
                cnt = 0;
            }
        }
    }

    return 0;
}
/**/

E.矩阵

2020 计蒜之道 线上决赛(C,D,E,F,G)

样例输入复制

2
11
10

样例输出复制

5

样例输入2

5
11100
11100
11110
11111
10000

样例输出 2

73

题解: 

2020 计蒜之道 线上决赛(C,D,E,F,G)

 我写的复杂度似乎有点问题? 再说吧,先把过的代码贴上来

std:

/**/
#pragma GCC optimize(3,"Ofast","inline")
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const int maxn = 1005;

int n, a[maxn][maxn], up[maxn][maxn], sk[maxn], sum[maxn][maxn], l[maxn];
char s[maxn][maxn];

void init(){
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= n; j++){
            sum[i][j] = (i % j == 0 || j % i == 0);
        }
    }
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= n; j++){
            sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
        }
    }
}

int cal(int n, int m){
    return sum[n][m];
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    scanf("%d", &n);
    init();
    for (int i = 1; i <= n; i++){
        scanf("%s", s[i] + 1);
        for (int j = 1; j <= n; j++) a[i][j] = s[i][j] - '0';
    }
    for (int j = 1; j <= n; j++){
        for (int i = 1; i <= n; i++){
            if(a[i][j] == 1) up[i][j] = up[i - 1][j] + 1;
            else up[i][j] = 0;
        }
    }
    LL ans = 0;
    for (int i = 1; i <= n; i++){
        int top = 0;
        for (int j = 1; j <= n; j++) l[j] = 0;
        for (int j = 1; j <= n; j++){
            while(top && up[i][sk[top]] >= up[i][j]) top--;
            sk[++top] = j;
            l[j] = j - sk[top - 1];
            if(!up[i][j]) continue;
            int sum = l[j];
            for (int k = top - 1; k >= 1; k--){
                ans += cal(up[i][sk[k]], sum += l[sk[k]]);
                ans -= cal(up[i][sk[k]], sum - l[sk[k]]);
            }
            ans += cal(up[i][j], l[j]);
            // printf("%d %d %d %lld\n", i, j, l[j], ans);
        }
    }
    printf("%lld\n", ans);

    return 0;
}
/*
7
1000000
1101110
1111111
0000000
0000000
0000000
0000000

5
00100
01110
11111
01110
00100
*/

F. 格子

2020 计蒜之道 线上决赛(C,D,E,F,G)

样例输入复制

3 2

样例输出复制

6

题解:

 2020 计蒜之道 线上决赛(C,D,E,F,G)

std:

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const long long mod = 998244353;
const int maxn = 2e6 + 5;

int n, m;
LL a[maxn];

LL poww(LL x, LL num){
    LL res = 1;
    while(num){
        if(num & 1) res = res * x % mod;
        x = x * x % mod;
        num >>= 1;
    }
    return res;
}

LL C(int n, int m){
    return a[n] * poww(a[m] * a[n - m] % mod, mod - 2) % mod;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    a[0] = 1;
    for (int i = 1; i < maxn; i++) a[i] = a[i - 1] * i % mod;
    scanf("%d %d", &n, &m);
    printf("%lld\n", C(n + m - 1, n - 1));

    return 0;
}
/**/

 

G. 宝藏

2020 计蒜之道 线上决赛(C,D,E,F,G)

样例输入复制

5 3
1 2 3 4 5
1 2 3
2 4 6
1 5 9

样例输出复制

36
1638
183600

题解:

2020 计蒜之道 线上决赛(C,D,E,F,G)

std:

/**/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <stack>
#include <queue>

typedef long long LL;
using namespace std;

const int maxn = 1e5 + 5;
const long long mod = 998244353;

int n, m, p[maxn][32], a[maxn];
LL pw2;

LL poww(LL x, LL num){
    LL res = 1;
    while(num){
        if(num & 1) res = res * x % mod;
        x = x * x % mod;
        num >>= 1;
    }
    return res;
}

LL cal(int a, int b, int x){
    return poww(x + 1, a) * (poww(1 + x, b) - poww((1 - x + mod) % mod, b) + mod) % mod * pw2 % mod;
}

int main()
{
    //freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);

    pw2 = poww(2, mod - 2);
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i <= n; i++){
        for (int j = 0; j < 30; j++){
            p[i][j] = p[i - 1][j];
            if(1 << j & a[i]) p[i][j]++;
        }
    }
    for (int i = 1, l, r, x; i <= m; i++){
        scanf("%d %d %d", &l, &r, &x);
        LL ans = 0;
        for (int j = 0; j < 30; j++){
            int b = p[r][j] - p[l - 1][j];
            int a = r - l + 1 - b;
            ans = (ans + 1LL * (1 << j) * cal(a, b, x) % mod) % mod;
        }
        printf("%lld\n", ans);
    }

    return 0;
}
/**/

 

本文地址:https://blog.csdn.net/oneplus123/article/details/109267743