ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2021牛客OI赛前集训营-提高组(第六场)解题报告

2021-10-18 08:32:41  阅读:157  来源: 互联网

标签:第六场 集训营 OI int LL long read ans include


比赛传送

得分:\(100 + 0 + 100 + 40 = 240pts\)

D 挂了 60 /ll

整套题比较屑。

A

观察一下他给的条件。

对于任意一个序列 \(a\),如果所有的 \(a_i \to a_i + k\),那么新的序列和原序列一样。

所以任意一个序列都有 \(m-1\) 个序列与之相同。

所以答案为总方案数除以 \(m\),即 \(m^{n-1}\)。

int Pow(int x, int p) {
    int res = 1;
    while(p) {
        if(p & 1) res = res * x % mod;
        x = x * x % mod, p >>= 1;
    }
    return res;
}

signed main()
{
    T = read();
    while(T--) {
    	n = read(), m = read();
        printf("%lld\n", Pow(m, n) * Pow(m, mod - 2) % mod);
    }
    return 0;
}

B

待补。

C

可以发现,如果中间存在一段连续的 \(0\),我们可以直接算出其插入的位置,然后可插入的区间被分成了两段。

显然可以用 set 去维护所有区间的信息,这样插入操作就能被很好的解决了。

考虑删除操作,可以对每个点维护一个链表,指向它在序列前一个位置的点和后一个位置的点。

有几个特殊的位置,如果可填左端点为 \(1\) 就直接在 \(1\) 填,如果可填右端点是 \(n\) 就直接在 \(n\) 填。

其余的就是一些细节问题了。

/*
Work by: Suzt_ilymics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define LL long long
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const int MAXN = 3e5+5;
const int INF = 1e9+7;
const int mod = 1e9+7;

struct node {
    int l, r, pos, len;
    bool operator < (const node &b) const {
        return len == b.len ? pos < b.pos : len > b.len;
    }
    void Init() {
        int Len = r - l + 1;
        pos = l + Len / 2;
        if(Len % 2 == 0) pos--;
        len = pos - l + 1;
    }
};

struct Node {
    int pre, pos, nxt;
}a[MAXN];

int n, m;
int ans[MAXN];
bool vis[MAXN];
set<node> S;
set<node>::iterator it;
map<int,int> Map;

int read(){
    int s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

int main()
{
//    freopen("C.in","r",stdin);
//    freopen("C.out","w",stdout);
    n = read(), m = read();
	S.insert((node){1, n, 1, n});
	it = S.begin();
	a[0].nxt = n + 1, a[m + 1].nxt = 0;
	a[0].pos = 0, a[m + 1].pos = n + 1;
	Map[0] = 0, Map[n + 1] = m + 1;
	for(int i = 1, x; i <= 2 * m; ++i) {
	    x = read();
	    if(!vis[x]) {
	        vis[x] = true;
	        node tmp = *S.begin();
	        S.erase(S.begin());
	        a[x].pos = tmp.pos;
            node res;
            res.l = tmp.l, res.r = a[x].pos - 1;
            if(res.l <= res.r) {
                if(res.l == 1) res.len = res.r, res.pos = 1;
                else res.Init();
                S.insert(res);
            }
            res.l = a[x].pos + 1, res.r = tmp.r;
            if(res.l <= res.r) {
                if(res.r == n) res.len = n - res.l + 1, res.pos = n;
                else res.Init();
                S.insert(res);
            }
            a[x].pre = Map[tmp.l - 1]; 
            a[x].nxt = Map[tmp.r + 1];
            a[a[x].pre].nxt = x;
            a[a[x].nxt].pre = x;
            Map[a[x].pos] = x;
            ans[x] = a[x].pos;
        } else {
            node tmp;
            tmp.l = a[a[x].pre].pos + 1;
            tmp.r = a[a[x].nxt].pos - 1;
            if(tmp.l == 1) {
                tmp.pos = 1;
                tmp.len = tmp.r;
            } else if(tmp.r == n) {
                tmp.pos = n;
                tmp.len = n - tmp.l + 1;
            } else {
                tmp.Init();
            }
            if(tmp.l <= a[x].pos - 1) {
                node res;
                res.l = tmp.l, res.r = a[x].pos - 1;
                res.Init();
                S.erase(*S.find(res));
            }
            if(a[x].pos + 1 <= tmp.r) {
                node res;
                res.l = a[x].pos + 1, res.r = tmp.r;
                res.Init();
                S.erase(*S.find(res));
            } 
            S.insert(tmp);
            a[a[x].pre].nxt = a[x].nxt;
            a[a[x].nxt].pre = a[x].pre;
            a[x].pos = a[x].nxt = a[x].pre = 0;
        }
    }
    for(int i = 1; i <= m; ++i) {
        printf("%d\n", ans[i]);
    }
    return 0;
}

D

题目保证最小生成树唯一,建出最小生成树来,然后两个点之间的简单路径也是唯一的,所以维护一个树上前缀和,相邻两个点的距离就可以快速算出,经过了多少点也可以算出。实现方式比较多样,当然你不嫌麻烦可以写树剖+线段树。

原题卡了 long long,记得开 __int128

/*
Work by: Suzt_ilymics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define LL long long
#define int __int128
#define orz cout<<"lkp AK IOI!"<<endl

using namespace std;
const LL MAXN = 2e5+5;
const LL INF = 1e9+7;
const LL mod = 1e9+7;

struct node {
    LL u, v, w;
    bool operator < (const node &b) const { return w < b.w; }
}b[MAXN];

LL n, m, K, t0;
int ans = 0;
LL a[1000010], fa[MAXN];
LL val[MAXN], pre[MAXN];

LL read(){
    LL s = 0, f = 0;
    char ch = getchar();
    while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    return f ? -s : s;
}

namespace Seg {
    #define lson i << 1
    #define rson i << 1 | 1
    LL sum[MAXN << 2];
    void Push_up(LL i) {
        sum[i] = sum[lson] + sum[rson];
    }
    void Build(LL i, LL l, LL r) {
        if(l == r) {
            sum[i] = val[pre[l]];
            return ;
        }
        LL mid= (l + r) >> 1;
        Build(lson, l, mid), Build(rson, mid + 1, r);
        Push_up(i);
    }
    LL Query(LL i, LL l, LL r, LL L, LL R) {
        if(L <= l && r <= R) return sum[i];
        LL mid = (l + r) >> 1, ans = 0;
        if(mid >= L) ans = ans + Query(lson, l, mid, L, R);
        if(mid < R) ans = ans + Query(rson, mid + 1, r, L, R);
        return ans;
    }
}

namespace Cut {
    struct edge {
        LL to, w, nxt;
    }e[MAXN << 1];
    LL head[MAXN], num_edge = 1;
    LL dep[MAXN], siz[MAXN], son[MAXN], Cnt = 0, dfn[MAXN], fath[MAXN], top[MAXN];
    void add_edge(LL from, LL to, LL w) { e[++num_edge] = (edge){to, w, head[from]}, head[from] = num_edge; }
    void dfs(LL u, LL fa) {
        fath[u] = fa, dep[u] = dep[fa] + 1, siz[u] = 1;
        for(LL i = head[u]; i; i = e[i].nxt) {
            LL v = e[i].to;
            if(v == fa) continue;
            val[v] = e[i].w;
            dfs(v, u);
            siz[u] += siz[v];
            if(siz[son[u]] < siz[v]) son[u] = v;
        }
    }
    void dfs2(LL u, LL tp) {
        top[u] = tp, dfn[u] = ++Cnt, pre[Cnt] = u;
        if(son[u]) dfs2(son[u], tp);
        for(LL i = head[u]; i; i= e[i].nxt) {
            LL v = e[i].to;
            if(v == son[u] || v == fath[u]) continue;
            dfs2(v, v);
        }
    }
    LL Get_LCA(LL u, LL v) {
        while(top[u] != top[v]) dep[top[u]] < dep[top[v]] ? v = fath[top[v]] : u = fath[top[u]];
        return dep[u] < dep[v] ? u : v;
    }
    LL Query(LL u, LL v) {
        LL ans = 0;
        while(top[u] != top[v]) {
            if(dep[top[u]] < dep[top[v]]) swap(u, v);
            ans = ans + Seg::Query(1, 1, n, dfn[top[u]], dfn[u]);
            u = fath[top[u]];
        }
        if(dep[u] > dep[v]) swap(u, v);
        if(u != v) ans = ans + Seg::Query(1, 1, n, dfn[u] + 1, dfn[v]);
        return ans;
    }
}

LL find(LL x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

void Print(int x){
    if(x > 9) Print(x / 10);
    putchar(x % 10 + '0');
}

signed main()
{
	n = read(), m = read();
	for(LL i = 1; i <= m; ++i) b[i].u = read(), b[i].v = read(), b[i].w = read();
    sort(b + 1, b + m + 1);
    for(LL i = 1; i <= n; ++i) fa[i] = i;
    for(LL i = 1, u, v, w; i <= m; ++i) {
        u = b[i].u, v = b[i].v, w = b[i].w;
        LL uf = find(u), vf = find(v);
        if(uf != vf) {
            fa[uf] = vf;
            Cut::add_edge(u, v, w), Cut::add_edge(v, u, w);
        }
    }
    Cut::dfs(1, 0), Cut::dfs2(1, 1), Seg::Build(1, 1, n);
    K = read(), t0 = read();
    for(LL i = 1; i <= K; ++i) a[i] = read();
    for(LL i = 2; i <= K; ++i) {
        LL u = a[i - 1], v = a[i];
        int Dis = Cut::Query(u, v);
        LL lca = Cut::Get_LCA(u, v);
        Dis = Dis + t0 * (Cut::dep[u] + Cut::dep[v] - 2 * Cut::dep[lca]);
        ans = ans + Dis;
    }
    Print(ans - t0);
    return 0;
}

标签:第六场,集训营,OI,int,LL,long,read,ans,include
来源: https://www.cnblogs.com/Silymtics/p/test-NK2021TG6.html

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

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

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

ICode9版权所有