ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

2021牛客寒假算法基础集训营2

2021-02-13 17:04:00  阅读:150  来源: 互联网

标签:return gcd int ll 牛客 flag 2021 集训营 lld


整出来了七道题,ABC最后都没做赛后补的

A题我和题解以及大部分人思路都不一样,并没有用到树状数组,我甚至看到有笛卡尔树做的(并不会),我是用了两次单调栈,维护两边最远的位置,再算贡献,然后这样写好像是代码长度最短的,应该是最简单的方法吧,但是这么写细节上也有很多坑,比如最小值不在区间内,在端点上时要特殊处理

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int a[N], x[N];
ll f[N][20], ans[N], dp[N], pre[N];
ll gcd(ll a, ll b) {
    return b ? gcd(b, a % b) : a;
}
inline void cal(ll a, ll b) {
    ll p = gcd(a, b);
    a /= p;
    b /= p;
    printf("%lld/%lld\n", a, b);
}
vector < int > v;
stack < int > s; 
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        f[i][0] = a[i];
    }
    for (int j = 1; j <= 20; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    int m;
    scanf("%d", &m);
    while (m--) {
        int k;
        scanf("%d", &k);
        for (int i = 1; i <= k; i++) {
            scanf("%d", &x[i]);
            ans[a[x[i]]]++; v.push_back(a[x[i]]);
        }
        sort(x + 1, x + k + 1);
        s.push(0); dp[0] = (1 << 30);
        for (int i = 1; i < k; i++) {
            int l = log2(x[i + 1] - x[i] + 1);
            ll q = max(f[x[i]][l], f[x[i + 1] - (1 << l) + 1][l]);
            dp[i] = q;
            while (!s.empty() && dp[s.top()] <= q)
                s.pop();
            pre[i] = (i - s.top());
            //ans[q] += 1ll * (i - s.top());
            s.push(i); 
        }
        while (!s.empty())    s.pop(); 
        s.push(k); dp[k] = (1 << 30);
        for (int i = k - 1; i >= 1; i--) {
            int l = log2(x[i + 1] - x[i] + 1);
            ll q = max(f[x[i]][l], f[x[i + 1] - (1 << l) + 1][l]);
            dp[i] = q; 
            while (!s.empty() && dp[s.top()] <= q)
                s.pop();
            if (dp[i] == dp[i + 1])    ans[q] += 2 * pre[i];
            else ans[q] += 1ll * 2 * (s.top() - i) * pre[i];
            v.push_back(q);
            s.push(i); 
        }
        while (!s.empty())    s.pop();
        sort(v.begin(), v.end());
        for (int i = 0; i < v.size(); i++) {
            if (i != 0 && v[i] == v[i - 1])    continue;
            printf("%d ", v[i]);
            cal(ans[v[i]], 1ll * k * k);
            ans[v[i]] = 0;
        }
        v.clear();
    }
    return 0;
}

C题很简单,但是有一个坑就是长度大于l/2时候要判断,刚开始没有注意到这个,WA了好多次

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int a[N], x[N];
ll f[N][20], ans[N], dp[N], pre[N];
ll gcd(ll a, ll b) {
    return b ? gcd(b, a % b) : a;
}
inline void cal(ll a, ll b) {
    ll p = gcd(a, b);
    a /= p;
    b /= p;
    printf("%lld/%lld\n", a, b);
}
vector < int > v;
stack < int > s; 
int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        f[i][0] = a[i];
    }
    for (int j = 1; j <= 20; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
            f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
    int m;
    scanf("%d", &m);
    while (m--) {
        int k;
        scanf("%d", &k);
        for (int i = 1; i <= k; i++) {
            scanf("%d", &x[i]);
            ans[a[x[i]]]++; v.push_back(a[x[i]]);
        }
        sort(x + 1, x + k + 1);
        s.push(0); dp[0] = (1 << 30);
        for (int i = 1; i < k; i++) {
            int l = log2(x[i + 1] - x[i] + 1);
            ll q = max(f[x[i]][l], f[x[i + 1] - (1 << l) + 1][l]);
            dp[i] = q;
            while (!s.empty() && dp[s.top()] <= q)
                s.pop();
            pre[i] = (i - s.top());
            //ans[q] += 1ll * (i - s.top());
            s.push(i); 
        }
        while (!s.empty())    s.pop(); 
        s.push(k); dp[k] = (1 << 30);
        for (int i = k - 1; i >= 1; i--) {
            int l = log2(x[i + 1] - x[i] + 1);
            ll q = max(f[x[i]][l], f[x[i + 1] - (1 << l) + 1][l]);
            dp[i] = q; 
            while (!s.empty() && dp[s.top()] <= q)
                s.pop();
            if (dp[i] == dp[i + 1])    ans[q] += 2 * pre[i];
            else ans[q] += 1ll * 2 * (s.top() - i) * pre[i];
            v.push_back(q);
            s.push(i); 
        }
        while (!s.empty())    s.pop();
        sort(v.begin(), v.end());
        for (int i = 0; i < v.size(); i++) {
            if (i != 0 && v[i] == v[i - 1])    continue;
            printf("%d ", v[i]);
            cal(ans[v[i]], 1ll * k * k);
            ans[v[i]] = 0;
        }
        v.clear();
    }
    return 0;
}

B题应该是最有意思的一道题了,并没有想出来怎么做,看到题解的时候感叹自己怎么这么菜,简单来说就是对每个状态建一个最短路树,然后像分层图一样连接起来,dfs一遍就可以了

记一下自己的很多坑,一直只通过了90%

1. 编号最小,需要用dis数组记录判断

2. 每次可以操纵多个开关

写的不是很优雅

#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = 110 * (1 << 11);
int p[11];
int n, m, k;
#define debug(x) cout << #x << " " << x << endl;
vector < int > edge[N], G[M];
inline void add(int u, int v) {
    edge[u].push_back(v);
}
int vis[M];
bool col[M][2];
queue < int > Q; 
inline void build(int flag) {
    int cnt = 0, b = flag;
    while (b) {
        cnt++; 
        if (b & 1)    vis[p[cnt] + flag * n] = (1 << 30);
        b >>= 1;
    }
    for (int j = 0; j < (1 << k); j++)
        if (j != flag) {
            for (int i = 1; i <= n; i++)
                G[j * n + i].push_back(flag * n + i);
        }
    if (vis[n + flag * n] == (1 << 30)) return ;
    Q.push(n); vis[n + flag * n] = 0;
    while (!Q.empty()) {
        int u = Q.front(); Q.pop();
        for (int i = 0; i < edge[u].size(); i++) {
            int v = edge[u][i];
            if (vis[v + flag * n] > vis[u + flag * n] + 1) {
                G[v + flag * n].push_back(u + flag * n);
                if (vis[v + flag * n] != (1 << 30))    Q.push(v);
                vis[v + flag * n] = vis[u + flag * n] + 1;
            }
            else if (vis[v + flag * n] == vis[u + flag * n] + 1)
                G[v + flag * n].back() = min(G[v + flag * n].back(), u + flag * n);
        }
    }
}

inline bool check(int u, int v) {
    return (u - 1) / n == (v - 1) / n;
}

stack < int > s;
bool dfs(int u, int flag) {
    bool tmp = false;
    col[u][flag] = true;
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (check(u, v) || !flag) {
            if (!col[v][!check(u, v)] && dfs(v, !check(u, v))) {
                s.push(u);
                return true;
            }
            tmp = true;
        }
    }
    if (!tmp && u % n != 0) {
        s.push(u);
        return true;
    }
    return false;
}

int main() {
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 1; i <= k; i++)
        scanf("%d", &p[i]);
    for (int i = 1; i <= m; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        add(u, v); add(v, u);
    }
    memset(vis, 0x3f, sizeof(vis));
    for (int i = 0; i < (1 << k); i++)
        build(i);
    //if (!dfs(1, 0)) return 0;
    dfs(1, 0);
    int last = (s.top() - 1) / n; s.pop();
    while (!s.empty()) {
        int u = s.top(); s.pop();
        u = (u - 1) / n;
        int k = last ^ u, cnt = 0;
        if (k == 0)
            printf("continue\n");
        else {
            while (k) {
                cnt++;
                if (k & 1) {
                    if (u & (1 << (cnt - 1))) printf("lock %d\n", p[cnt]);
                    else     printf("unlock %d\n", p[cnt]);
                }
                k >>= 1;
            }
        }
        last = u;
    }
    puts("checkmate!");
    return 0;
}

 

标签:return,gcd,int,ll,牛客,flag,2021,集训营,lld
来源: https://www.cnblogs.com/cminus/p/14400341.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有