Codeforces Round #442 (Div. 2)【solved : 6 / 6】

来源:互联网 发布:产品矩阵是什么意思 编辑:程序博客网 时间:2024/06/06 01:16

A - Alex and broken contest (water)

#include <bits/stdc++.h>using namespace std;char a[][20] = {"Danil", "Olya", "Slava", "Ann", "Nikita"};char s[105];bool judge(int id, int st, int sublen){    for(int i = 0; i < sublen; i++)        if(s[st + i] != a[id][i])   return false;    return true;}int main(){    scanf("%s", s);    int len = strlen(s), cnt = 0;    for(int i = 0; i < 5; i++)    {        int sublen = strlen(a[i]);        for(int j = 0; j + sublen - 1 < len; j++)        {            if(judge(i, j, sublen)) cnt++;        }    }    puts(cnt == 1 ? "YES" : "NO");    return 0;}

B - Nikita and string (思维)

题意:给你一个只包含a、b的子串,让选出一个子序列,满足第一部分全为a,第二部分全为b,第三部分全为a(各个部分可为空),问你这个子序列最长为多少。串长5000。

思路:用前缀和维护a的数量。然后枚举前两个部分的长度,即可。

#include <bits/stdc++.h>using namespace std;const int maxn = 5000 + 5;char s[maxn];int cnta[maxn];int main(){    scanf("%s", s + 1);    int len = strlen(s + 1);    for(int i = 1; i <= len; i++)   cnta[i] = cnta[i - 1] + (s[i] == 'a');    int ans = 0;    for(int i = 0; i <= len; i++)    {        for(int j = 0; i + j <= len; j++)        {            int cnt1 = cnta[i];            int cnt2 = j - (cnta[i + j] - cnta[i]);            int cnt3 = cnta[len] - cnta[i + j];            ans = max(ans, cnt1 + cnt2 + cnt3);        }    }    printf("%d\n", ans);    return 0;}

C - Slava and tanks (构造)

题意:一排1*n的方格,每个方格内都有坦克,每个坦克被攻击第一次的时候会往两侧逃逸,被攻击第二次时被击毁。请给出方案,使得用最少的攻击方式,击毁所有坦克。n100000

思路:将偶数位依次攻击一遍,所有的坦克逃至奇数位,再攻击一遍奇数位,击毁原先逃逸的坦克,然后存活的坦克逃至偶数位,再攻击一遍偶数位即可。

#include <bits/stdc++.h>using namespace std;int main(){    int n;    scanf("%d", &n);    vector<int>vec;    for(int i = 2; i <= n; i+=2)    vec.push_back(i);    for(int i = 1; i <= n; i+=2)    vec.push_back(i);    for(int i = 2; i <= n; i+=2)    vec.push_back(i);    printf("%d\n", vec.size());    for(int i = 0; i < vec.size(); i++) printf("%d%c", vec[i], " \n"[i + 1 == vec.size()]);    return 0;}

D - Olya and Energy Drinks (bfs)

题意:给出一个1000*1000的迷宫,然后给出初始点和终点,然后每次能沿着上下左右其中一个方向移动最多k步。问最少需要几步走到终点。

思路:
  直接bfs显然会超时。容易得到状态一共有1000×1000×4个,标记一下即可。
  剪枝呢就是,考虑到每次抵达点(x,y)的时候,如果(x,y,dir)已经访问过了,显然可以break。

#include <bits/stdc++.h>using namespace std;const int maxn = 1000 + 5;const int INF = 0x3f3f3f3f;char ma[maxn][maxn];int dp[maxn][maxn];bool vis[maxn][maxn][4];int n, m, k, sx, sy, gx, gy;int dx[] = {0, 0, 1, -1};int dy[] = {1, -1, 0, 0};int bfs(){    memset(dp, INF, sizeof(dp));    memset(vis, 0, sizeof(vis));    queue<pair<int, int>>que;    que.push({sx, sy});    dp[sx][sy] = 0;    for(int i = 0; i < 4; i++)    vis[sx][sy][i] = 1;    while(que.size())    {        pair<int, int> cur = que.front();que.pop();        if(cur.first == gx && cur.second == gy) return dp[cur.first][cur.second];        for(int i = 0; i < 4; i++)        {            int step = 1;            while(step <= k)            {                int fx = cur.first + dx[i] * step;                int fy = cur.second + dy[i] * step;                if(!(1 <= fx && fx <= n && 1 <= fy && fy <= m && ma[fx][fy] == '.' && vis[fx][fy][i] == 0))    break;                if(dp[cur.first][cur.second] + 1 > dp[fx][fy])  break;                vis[fx][fy][i] = 1;                dp[fx][fy] = dp[cur.first][cur.second] + 1;                que.push({fx, fy});                step++;            }        }    }    return -1;}int main(){    scanf("%d%d%d", &n, &m, &k);    for(int i = 1; i <= n; i++) scanf("%s", ma[i] + 1);    scanf("%d%d%d%d", &sx, &sy, &gx, &gy);    printf("%d\n", bfs());    return 0;}

E - Danil and a Part-time Job (dfs序+线段树)

题意:给出一棵n个结点树,然后每个点开关灯的状态。然后给出q次操作,操作1:统计子树x内的开灯的结点数量,操作2:把字数内的所有开关的状态翻转。nq100000

思路:
  dfs序一下,可以发现是一个区间和的查询,和一个区间修改的操作,加个线段树即可。

#include <bits/stdc++.h>using namespace std;const int maxv = 200000 + 5;vector<int>G[maxv];int a[maxv], b[maxv], in[maxv], out[maxv];int tim;void dfs(int cur, int fa){    in[cur] = ++tim;    b[tim] = a[cur];    for(auto o : G[cur])    if(o != fa)    {        dfs(o, cur);    }    out[cur] = tim;}const int maxn = maxv << 2 + 5;int tree[maxn], lazy[maxn];#define lson l, mid, rt << 1#define rson mid + 1, r, rt << 1 | 1void pushup(int rt){tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];}void build(int l, int r, int rt){    if(l == r)    {        tree[rt] = b[l];        return ;    }    int mid = (l + r) / 2;    build(lson);    build(rson);    pushup(rt);}void pushdown(int l, int r, int rt){    if(lazy[rt])    {        int mid = (l + r) / 2;        tree[rt << 1] = (mid - l + 1) - tree[rt << 1];        tree[rt << 1 | 1] = (r - (mid + 1) + 1) - tree[rt << 1 | 1];        lazy[rt << 1] ^= 1;        lazy[rt << 1 | 1] ^= 1;        lazy[rt] = 0;    }}int query(int ql, int qr, int l, int r, int rt){    if(ql <= l && r <= qr)  return tree[rt];    pushdown(l, r, rt);    int ret = 0, mid = (l + r) / 2;    if(ql <= mid)   ret += query(ql, qr, lson);    if(qr > mid)    ret += query(ql, qr, rson);    return ret;}void update(int ql, int qr, int l, int r, int rt){    if(ql <= l && r <= qr)    {        tree[rt] = (r - l + 1) - tree[rt];        lazy[rt] ^= 1;        return ;    }    pushdown(l, r, rt);    int mid = (l + r) / 2;    if(ql <= mid)   update(ql, qr, lson);    if(qr > mid)    update(ql, qr, rson);    pushup(rt);}int main(){    int n;    scanf("%d", &n);    for(int i = 2, x; i <= n; i++)    {        scanf("%d", &x);        G[x].push_back(i);    }    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);    tim = 0;    dfs(1, -1);    build(1, n, 1);    int q;    scanf("%d\n", &q);    while(q--)    {        char cmd[10];        int id;        scanf("%s %d", cmd, &id);        if(cmd[0] == 'g')        {//get            printf("%d\n", query(in[id], out[id], 1, n, 1));        }        else        {//swith            update(in[id], out[id], 1, n, 1);        }    }    return 0;}

F - Ann and Books (莫队算法)

题意:详见原题?

思路:
  显然我们是可以采用莫队来解决。用一个前缀和来维护一下的话,就转变成在区间[l,r]内,x<=y且a[y] = a[x-1] + k的数对(x,y)有几个。
  我们考虑[l,r] -> [l,r+1],此时,a[r + 1]这个数出现的次数++,对答案的贡献度应该是a[r + 1]-k这个数出现的次数。
  我们考虑[l,r] -> [l - 1,r+1],此时,a[l-1]这个数出现的次数++,对答案的贡献度应该是a[l - 1]+k这个数出现的次数。
  [l,r] -> [l + 1,r]和[l,r - 1]亦是同理。所以我们可以发现我们需要维护一个val出现的次数即可。然后处理完以上,还要处理一个x=l-1的特殊情况。
  然后因为数据范围很大的原因,所以需要一个离散化。离散化有蛮多的小细节需要注意。
  以上。

#include <bits/stdc++.h>using namespace std;const int maxn = 100000 + 5;int ty[maxn], qian[maxn], hou[maxn];long long tong[maxn], a[maxn], ans[maxn];int cnt = 0;long long kind;struct node{int l, r, block, id;}q[maxn];void erase1(int p){    tong[a[p]]--;    if(hou[a[p]])   kind -= tong[hou[a[p]]];}inline void erase2(int p){    tong[a[p]]--;    if(qian[a[p]])  kind -= tong[qian[a[p]]];}inline void insert1(int p){    if(hou[a[p]])   kind += tong[hou[a[p]]];    tong[a[p]]++;}inline void insert2(int p){    if(qian[a[p]])  kind += tong[qian[a[p]]];    tong[a[p]]++;}vector<long long>vec;map<long long, int>ma;int main(){    int n, k;    scanf("%d%d", &n, &k);    for(int i = 1; i <= n; i++) scanf("%d", &ty[i]);    for(int i = 1; i <= n; i++)    {        scanf("%lld", &a[i]);        a[i] = a[i] * (ty[i] == 1 ? 1 : -1) + a[i - 1];        vec.push_back(a[i]);    }    sort(vec.begin(), vec.end());    vec.resize(unique(vec.begin(), vec.end()) - vec.begin());    for(auto o : vec)   ma[o] = ++cnt;    for(int i = 1; i <= n; i++)    {        int idx = ma[a[i]];        qian[ma[a[i]]] = ma[a[i]-k];        hou[ma[a[i]]] = ma[a[i]+k];        a[i] = idx;    }    hou[0] = ma[k];    int m, len = sqrt(n);    scanf("%d", &m);    for(int i = 1; i <= m; i++)    {        int l, r;        scanf("%d%d", &l, &r);        q[i] = {l, r, l / len, i};    }    sort(q + 1, q + m + 1, [](node &x, node &y)         {             return x.block < y.block || (x.block == y.block && x.r < y.r);         });    int lb = q[1].l, rb = q[1].l - 1;    for(int i = 1; i <= m; i++)    {        while(lb>q[i].l)    insert1(--lb);        while(rb<q[i].r)    insert2(++rb);        while(lb<q[i].l)    erase1(lb++);        while(rb>q[i].r)    erase2(rb--);        ans[q[i].id] = kind + tong[hou[a[lb-1]]];    }    for(int i = 1; i <= m; i++) printf("%lld\n", ans[i]);    return 0;}
原创粉丝点击