codeforces round #416 div2

A:暴力模拟

#include<bits/stdc++.h>
using namespace std;
int a, b;
int main()
{
    scanf("%d%d", &a, &b);
    int delta = 1, x = 0;
    while(1)
    {
        if(x == 0)
        {
            if(a < delta)
            {
                puts("Vladik");
                return 0;
            }
            a -= delta; ++delta;
            x ^= 1;
        }
        else
        {
            if(b < delta)
            {
                puts("Valera");
                return 0;
            }
            b -= delta; ++delta;
            x ^= 1;
        }
    }
    return 0;
}

B:先写了个sort竟然pp了,过了十分钟感觉不太好,又写了个基数排序

#include<bits/stdc++.h>
using namespace std;
const int N = 20010;
int n, m;
int p[N], a[N], b[N];
bool cp(int i, int j) { return i < j; }
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) scanf("%d", &p[i]);
    while(m--)
    {
        int l, r, x, temp; scanf("%d%d%d", &l, &r, &x);
        for(int i = l; i <= r; ++i) a[i] = p[i], b[p[i]] = 1;
        temp = p[x];
        int pos1 = l, pos2 = 1;
        while(pos1 <= r)
        {
            while(!b[pos2]) ++pos2; b[pos2] = 0;
            a[pos1] = pos2; ++pos1;
        }
        if(a[x] == temp) puts("Yes"); else puts("No");
    }
    return 0;
}

C:dp什么的滚吧。。。dp[i]表示到i的最大值,那么我们枚举i-1每个数选不选,转移一下即可

#include<bits/stdc++.h>
using namespace std;
const int N = 5010;
int n;
int a[N], l[N], r[N], f[N], vis[N];
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i)
    {
        scanf("%d", &a[i]);
        r[a[i]] = i;
        if(!l[a[i]]) l[a[i]] = i;
    }
    for(int i = 1; i <= n; ++i)
    {
        f[i] = max(f[i], f[i - 1]); int cur = 0;
        memset(vis, 0, sizeof(vis));
        int last = 1 << 29;
        for(int j = i; j >= 0; --j)
        {
            if(last == j) f[i] = max(f[i], f[j] + cur);
            if(r[a[j]] > i) break;
            if(!vis[a[j]])
            {
                cur ^= a[j];
                vis[a[j]] = 1;
                last = min(last, l[a[j]] - 1);
            }
        }
    }
    printf("%d\n", f[n]);
    return 0;
}

D:没看懂题目

E:很不错的一道题 我们用线段树维护每一层的值和并查集 然后查询的时候把并查集复原合并 太巧妙了 这个并查集复原想了很长时间 思路是这个样子的:因为对于两块东西 原来是不相连的

但是build完和query完并查集都会变 那么我们在build的时候用并查集维护每个节点的连通性 保存两侧的当前并查集中的根是谁。 查询的时候把根的fa赋成自己 因为这个fa代表了原来的连通块

然后之后的节点合并改变了根 那么我们想要回到原来的状态把根赋成单独的一块就行了 然后要注意更新ret要在外面更新 因为可能下面和上面会连接 否则并查集不能及时地更新

#include<bits/stdc++.h>
using namespace std;
#define id(i, j) (i - 1) * m + j
const int N = 1000010;
struct data {
    int sum, l[12], r[12], L, R;
} tree[N];
int n, m, q;
int fa[N], a[12][N];
int find(int x)
{
    return fa[x] == x ? x : fa[x] = find(fa[x]);//fa[x] = find(fa[x]);
}
void connect(int x, int y)
{
    int a = find(x), b = find(y);
    if(a == b) return;
    fa[a] = b;
}
data merge(data x, data y, int mid)
{
    if(!x.sum) return y;
    if(!y.sum) return x;
    data ret;
    ret.sum = x.sum + y.sum;
    for(int i = 1; i <= n; ++i)
    {
        fa[x.l[i]] = x.l[i];
        fa[x.r[i]] = x.r[i];
        fa[y.l[i]] = y.l[i];
        fa[y.r[i]] = y.r[i];
     }
    for(int i = 1; i <= n; ++i)
        if(a[i][mid] == a[i][mid + 1])
        {
            if(find(x.r[i]) != find(y.l[i])) connect(x.r[i], y.l[i]), --ret.sum;
        }
    for(int i = 1; i <= n; ++i)
    {
        ret.l[i] = find(x.l[i]);
        ret.r[i] = find(y.r[i]);
    }
    ret.L = x.L; ret.R = y.R;
    return ret;
}
void build(int l, int r, int x)
{
    if(l == r)
    {
        for(int i = 1; i <= n; ++i)
            if(a[i][l] == a[i - 1][l])
            {
                fa[id(i, l)] = tree[x].l[i] = tree[x].r[i] = tree[x].l[i - 1];
            }
            else fa[id(i, l)] = tree[x].l[i] = tree[x].r[i] = id(i, l), ++tree[x].sum;
        tree[x].L = l; tree[x].R = r;
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1);
    tree[x] = merge(tree[x << 1], tree[x << 1 | 1], mid);
}
data query(int l, int r, int x, int a, int b)
{
    if(l > b || r < a) return tree[0];
    if(l >= a && r <= b)
    {
        for(int i = 1; i <= n; ++i)
            fa[id(i, l)] = tree[x].l[i], fa[id(i, r)] = tree[x].r[i];
        return tree[x];
    }
    int mid = (l + r) >> 1;
    data L = query(l, mid, x << 1, a, b);
    data R = query(mid + 1, r, x << 1 | 1, a, b);
    return merge(L, R, mid);
}
int main()
{
    scanf("%d%d%d", &n, &m, &q);
    for(int i = 1; i <= n; ++i)
        for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j]);
    build(1, m, 1);
    while(q--)
    {
        int l, r; scanf("%d%d", &l, &r);
        printf("%d\n", query(1, m, 1, l, r).sum);
    }
    return 0;
}

时间: 2024-12-07 03:31:41

codeforces round #416 div2的相关文章

codeforces round #257 div2 C、D

本来应该认真做这场的,思路都是正确的. C题,是先该横切完或竖切完,无法满足刀数要求,再考虑横切+竖切(竖切+横切), 因为横切+竖切(或竖切+横切)会对切割的东西产生交叉份数,从而最小的部分不会尽可能的大. 代码如下,虽然比较长.比较乱,但完全可以压缩到几行,因为几乎是4小块重复的代码,自己也懒得压缩 注意一点,比如要判断最小块的时候,比如9行要分成2份,最小的剩下那份不是9取模2,而应该是4 m/(k+1)<=m-m/(k+1)*k          #include<bits/stdc+

codeforces Round #250 (div2)

a题,就不说了吧 b题,直接从大到小排序1-limit的所有数的lowbit,再从大到小贪心组成sum就行了 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #define N 200000 6 using namespace std; 7 int pos[N],a[N],s[N],f[N],la[N],b[N],i,j,k,ans,n,p

Codeforces Round #416 (Div. 2) C. Vladik and Memorable Trip

题目链接:Codeforces Round #416 (Div. 2) C. Vladik and Memorable Trip 题意: 给你n个数,现在让你选一些区间出来,对于每个区间中的每一种数,全部都要出现在这个区间. 每个区间的价值为该区间不同的数的异或值,现在问你这n个数最大的价值是多少. 题解: 比赛的时间直接就想到了做法,不过在选取合法区间的时候,细节上出了点小问题. 然后一直wa到怀疑人生.太菜了. 首先,先将合法的区间选取出来. 对于这些区间,按照左端点排序, 然后对于选出来的

Codeforces Round#320 Div2 解题报告

Codeforces Round#320 Div2 先做个标题党,骗骗访问量,结束后再来写咯. codeforces 579A Raising Bacteria codeforces 579B Finding Team Member codeforces 579C A Problem about Polyline codeforces 579D "Or" Game codeforces 579E Weakness and Poorness codeforces 579F LCS Aga

Codeforces Round #254(div2)A

很有趣的题.想到了就非常简单,想不到就麻烦了. 其实就是一种逆向思维:最后结果肯定是这样子: WBWBWBWB... BWBWBWBW... WBWBWBWB... ... 里面有“-”的地方改成“-”就行了. 但是我开始是正着想的,想每个点怎么处理,这还要看它周围点的状态,越想越麻烦... 这题中体现的正难则反的逆向思维很值得学习. #include<iostream> #include<cstdio> #include<cstdlib> #include<cs

Codeforces Round #254(div2)B

就是看无向图有几个连通块,答案就是2n-num. 范围很小,就用矩阵来存图减少代码量. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set> #include<vector> #include<algorithm> #inc

Codeforces Round #260(div2)C(递推)

有明显的递推关系: f[i]表示i为数列中最大值时所求结果.num[i]表示数i在数列中出现了几次. 对于数i,要么删i,要么删i-1,只有这两种情况,且子问题还是一样的思路.那么很显然递推一下就行了:f[i]=max(f[i-1],f[i-2]+i*num[i]); 这里技巧在于:为了防止麻烦,干脆就所有数的出现次数都记录一下,然后直接从2推到100000(类似于下标排序),就不用排序了,也不用模拟删除操作了.这一技巧貌似简单,但实际上临场想出来也需要点水平. #include<iostrea

Codeforces Round #289 Div2 E

Problem 给一串长度为N的字符串,对于每个字符,若字符为元音,则权值为1,否则为0.一个子串的权值定义为该串所有字符权值之和除以字符个数,一个母串的权值定义为所有子串的权值之和.求母串的权值. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N: [1, 5*10^5] 字符集: 'A'-'Z' 元音: I E A O U Y Solution 考虑每个元音字符对母串的贡献,可以找出规律. More 举"ABCDOEFGHKMN"

Codeforces Round #403 div2 C. Andryusha and Colored Balloons

题目链接:Codeforces Round #403 div2 C. Andryusha and Colored Balloons 题意: 给你一棵n个节点的树,然后让你染色,规定相连的三个 节点不能同色,问需要的最少颜色,并输出其中一种方案. 题解: 因为只有相邻3个节点不同色. 所以直接DFS,每个节点都从1开始. 然后ans[v]!=ans[u]!=ans[fa]就行. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i&