Codeforces Round #605(Div3)A~E

Codeforces Round #605(Div3)A~E

A. Three Friends

题意:

  • 给三个数\(a,b,c\),对每一个数字可以进行一次操作,加一减一或者不变。
  • 求三个数两两组合的差值绝对值的最小值。

思路:

  • 先排个序。
  • 假设排序后三个数从小到大是\(a,b,c\)。
  • 那么他们的两两差就是\((c-b)+(c-a)+(b-a)=2c-2a\)。
  • 为了让他们的\(2c-2a\)最小,那就缩小\(c\),增大\(a\)。
#include<bits/stdc++.h>
using namespace std;
void solve()
{
    int a[3];
    for(int i = 0; i < 3; i++)
        cin >> a[i];
    sort(a, a+3);
    if(a[0] < a[2]) a[0]++;
    if(a[2] > a[0]) a[2]--;
    cout << 2*(a[2]-a[0]) << endl;
}

int main()
{
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}

B. Snow Walking Robot

题意:

  • 给出一串指令,最后回到原点,除了起点之外同一个地方不能经过两次。
  • 你可以删除指令集中的一些指令或重组这些指令,问最多能走多少步。

思路:

  • 构造题。
  • 首先可以发现,L和R,U和D之间是可以相互抵消的。
  • 那么我们只需要从这两个数字中取min即可。
  • 剩下的让他们绕一个正方形。
  • 值得注意的是,如果上下或左右某一方没有的时候,另一边只能为1,因为一个格子不能走两次。
#include<bits/stdc++.h>
using namespace std;

void solve()
{
    string str;
    cin >> str;
    int l, r, u, d;
    l = r = u = d = 0;
    for(auto x : str)
    {
        if(x == 'L') l++;
        if(x == 'R') r++;
        if(x == 'U') u++;
        if(x == 'D') d++;
    }
    int num1 = min(l, r);
    int num2 = min(u, d);

    if(num1 == 0 || num2 == 0)
    {
        num1 = min(num1, 1);
        num2 = min(num2, 1);
    }

    string ans = "";
    for(int i = 1; i++ <= num1;)
        ans += 'L';
    for(int i = 1; i++ <= num2;)
        ans += 'U';
    for(int i = 1; i++ <= num1;)
        ans += 'R';
    for(int i = 1; i++ <= num2;)
        ans += 'D';
    cout << ans.size() << endl;
    cout << ans << endl;
}

int main()
{
    int T; scanf("%d", &T);
    while(T--) solve();
    return 0;
}

C. Yet Another Broken Keyboard

题意:

  • 给你一个字符串,小明想要练习自己的打字速度,所以他打算输入所有的子串。
  • 但是键盘坏了,有部分键不能使了,问在这种情况下,小明还能输入多少个子串。

思路:

  • 对于一个字符串而言,他有\(\frac{n(n+1)}{2}\)个子串。
  • 那么可以把原先的字符串拆解成可以用键盘输入的几个字符串,然后直接计算答案就行。
#include<bits/stdc++.h>
using namespace std;
int n, k;
int vis[30]; //可以用的键位
string str;

int main()
{
    int n, k;
    cin >> n >> k;
    cin >> str;
    for(int i = 1; i <= k; i++)
    {
        char c[2];
        scanf("%s", c);
        vis[c[0]-'a']++;
    }
    //有溢出风险, 记得开longlong
    long long ans = 0;
    for(int i = 0; i < n; i++)
    {
        if(vis[str[i]-'a']) //如果当前位置可以
        {
            long long num = 0; //统计连续的可以的串
            for(int j = i; j < n; j++)
            {
                i = j;
                if(vis[str[j]-'a']) num++;
                else break;
            }
            ans += num*(num+1) / 2;
        }
    }
    cout << ans << endl;
    return 0;
}

D. Remove One Element

题意:

  • 给你一个长度为n的序列a。
  • 你可以最多从序列中删除一个数字,最终的序列长度为\(n-1\)或者\(n\)。
  • 你需要找到最长的可能的严格上升的子序列(这个子序列是连续的)。

思路:

  • 假如说没有删除一个数字的条件的话,这题应该怎么写?
  • 设\(f(i)\)表示前\(i\)个数字中,最长的严格上升的子序列长度为多少。
  • 那么有递推方程:
    • \(if(a(i)>a(i-1))\ f(i)=f(i-1)+1,else\ f(i)=1\)。
  • 现在要删除某个数字,让序列变长,假设说删除的是第\(i\)号位置上的数字,那么如果\(a(i+1)>a(i-1)\),就可以快速的计算出\(i-1\)前面有多少个连续的严格上升的数字,但是后面的就不是很好计算,是\(O(n)\)的。
  • 所以设\(g(i)\)表示以第\(i\)个数字为开头,最多能有多长的合法子序列。
  • 枚举删除位置,用\(f(i-1)+g(i+1)\)更新答案。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int n, a[maxn], ans;
int f[maxn], g[maxn];
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);

    f[1] = ans = 1;
    for(int i = 2; i <= n; i++)
    {
        f[i] = 1;
        if(a[i] > a[i-1]) f[i] = f[i-1]+1;
        ans = max(f[i], ans);
    }

    g[n] = 1;
    for(int i = n-1; i >= 1; i--)
    {
        g[i] = 1;
        if(a[i] < a[i+1]) g[i] = g[i+1]+1;
    }
    ans = max(ans, g[1]);
    for(int i = 2; i <= n-1; i++)
        if(a[i+1]>a[i-1])
        ans = max(ans, f[i-1]+g[i+1]);
    ans = max(ans, f[n]);
    cout << ans << endl;
    return 0;
}

E. Nearest Opposite Parity

题意:

  • 有一个长度为n的序列a。
  • 每一步你可以从第\(i\)个位置跳跃到第\(i-a_i\)或\(i+a_i\)。(当然\(1\leq i-a_i,i+a_i\leq n\))。
  • 对于每一个\(i\),你想知道他到\(j\)的最小步数,其中\(a_i,a_j\)奇偶性不同。

思路:

  • 每个点可以跳到另一个点,所以不妨把整张图看成有\(n\)个点,至多有\(2n\)条边的有向图。
  • 首先根据输入的数据进行建图。如果一个点\(x\)可以到\(y\),那么就建立一条从\(y\)到\(x\)的边。
  • 之后进行bfs。
  • 先加入偶数点入队列,就相当于以偶数点为终点(因为是反向建图),去找最近的可以到他的奇数点,同时更新答案。
  • 奇数点同理。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn], n;

int head[maxn], nex[maxn<<2], ver[maxn<<2], tot;
inline void add_edge(int x, int y){
    ver[++tot] = y; nex[tot] = head[x]; head[x] = tot;
}

int path[maxn][3];

void bfs(int dir)
{
    queue<int> q;
    for(int i = 1; i <= n; i++)
    {
        if(a[i] % 2 == dir)
        {
            path[i][dir] = 0;
            q.push(i);
        } else {
            path[i][dir] = -1;
        }
    }

    while(q.size())
    {
        int x = q.front(); q.pop();
        for(int i = head[x]; i; i = nex[i])
        {
            int y = ver[i];
            if(path[y][dir] == -1)
            {   //代表是从奇偶性不同的点转移过来的
                path[y][dir] = path[x][dir]+1;
                q.push(y);
            }
        }
    }
}

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for(int i = 1; i <= n; i++)
    {
        if(i + a[i] <= n) add_edge(i+a[i], i);
        if(i - a[i] >= 1) add_edge(i-a[i], i);
    }

    bfs(0); bfs(1);
    for(int i = 1; i <= n; i++)
    {
        if(a[i] % 2) printf("%d ", path[i][0]);
       else printf("%d ", path[i][1]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zxytxdy/p/12245992.html

时间: 2024-10-08 13:39:22

Codeforces Round #605(Div3)A~E的相关文章

【赛时总结】◇赛时&#183;V◇ Codeforces Round #486 Div3

◇赛时·V◇ Codeforces Round #486 Div3 又是一场历史悠久的比赛,老师拉着我回来考古了--为了不抢了后面一些同学的排名,我没有做A题 ◆ 题目&解析 [B题]Substrings Sort +传送门+   [暴力模拟] 题意 给出n个字符串,你需要将它们排序,使得对于每一个字符串,它前面的字符串都是它的子串(对于字符串i,则字符串 1~i-1 都是它的子串). 解析 由于n最大才100,所以 O(n3) 的算法都不会爆,很容易想到暴力模拟. 如果字符串i是字符串j的子串

CodeForces Round #527 (Div3) C. Prefixes and Suffixes

http://codeforces.com/contest/1092/problem/C Ivan wants to play a game with you. He picked some string ss of length nn consisting only of lowercase Latin letters. You don't know this string. Ivan has informed you about all its improper prefixes and s

Codeforces Round #605 (Div. 3) E - Nearest Opposite Parity

题目链接:http://codeforces.com/contest/1272/problem/E 题意:给定n,给定n个数a[i],对每个数输出d[i]. 对于每个i,可以移动到i+a[i]和i-a[i](如果i+a[i]<=n,i-a[i]>=1) d[i]是指从i移动到任意一个j的步数,需满足条件a[i]和a[j]的奇偶性不同 不论奇偶,相连的边先放进vector邻接表中 如果i和i+a[i]奇偶性不同,那么ans[i]为1,把i放到queue队列里 同理,如果i和i-a[i]奇偶性不同

Codeforces Round #605 (Div. 3)

地址:http://codeforces.com/contest/1272 A. Three Friends 仔细读题能够发现|a-b| + |a-c| + |b-c| = |R-L|*2 (其中L = min{a, b, c}, R = max{a, b, c}) 那么本题的移动条件就只考虑两个端点L, R即可,答案即为 |(L+1)-(R-1)| 即L向右移动1,R向左移动1,在此之前判断一下原L,R之间的距离是否<=2,<=2输出0 #include <bits/stdc++.h&

CodeForces Round #498 div3

A: 题目没读, 啥也不会的室友帮我写的. 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define f

D. Circular Dance codeforces round#529(div3)

这道题类似与经典题目素数和环,每次找到后两个数字a,b,如果a没被访问过且a是b的父节点(a记得b),就继续把a当下一个节点搜,否则把b当下一个节点搜 值得注意的是当搜到只剩下一个节点的时候,要选取那个没有访问过的节点做最后一个节点,因此需要标记数组 #include<bits/stdc++.h> using namespace std; int a[200010],b[200010]; bool vis[200010]; int n; void dfs(int step,int num) {

Codeforces Round #555 div3 C2

题目大意 给出一个序列,可以从左或从右侧取数,要求取出的序列严格上升 思路 贪心取左右最小的,如果相等则之后只能从一侧取,直接选能取最长的一侧 Code: #include<bits/stdc++.h> #define ll long long #define inf 0x3f3f3f3f using namespace std; int ma[10]; int n; int a[(int)(2*1e5)+10]; int main(){ scanf("%d",&n

Codeforces Round #560 div3 (C,D)

C 题目大意: 给出一个字符串,可以删除任意位置上的字符,得到一个好字符串. 长度为偶数,且奇数位置i上的字符与\(i+1\)上的字符不相等. 求最小的操作次数 思路: 暴力,遇到奇数位置与后面位置相同直接删除,注意是答案字符串上的奇数位置 #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<iostream> #include<algor

Codeforces Round #605 (Div. 3) E - Nearest Opposite Parity (超级源点)

?? ?? ?? 题意:一个数组,i位置可以到达i +/- a[ i ] 位置(不越界情况下),问你每个位置要走到一个奇偶性相反的地点最少要走几次, 在现场,,然而我真的不会哈哈哈哈我好菜?? 主要是两点:超级源点(多源变单源)+ 反向建边(反向思维) 建立一个超级奇数点,一个超级偶数点: 超级奇数点为例,从该点出发,配合我们建立的反向边, 如果可以到达某个偶数点,求得的距离肯定是所有能到达他的奇数点中最小的(最短路中任意一条子路最短) 还有就是图里面写搜索记得开vis,,,树里面搜索可以不写,