AtCoder Beginner Contest 261 (ABC 261) B~F 题解

  • Post author:
  • Post category:其他




B –

Tournament Result



题目大意

给你



n

n






n





支队伍,给出他们的输赢情况,判断是否冲突。



思路

我们设赢为



1

1






1





,输为



0

0






0





,平为



1

-1









1





,则当



a

i

,

j

+

a

j

,

i

0

a_{i, j} + a_{j, i} \not= 0







a











i


,


j





















+









a











j


,


i












































=








0





时,则存在冲突。



代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, a[1005][1005];
int in() {
    char s = getchar();
    while (s != '-' && s != 'W' && s != 'D' && s != 'L')
        s = getchar();
    if (s == 'W')
        return 1;
    if (s == 'D')
        return 2;
    if (s == 'L')
        return 3;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            a[i][j] = in();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j < i; j++)
            if (a[i][j] + a[j][i] != 4) {
                printf("incorrect");
                return 0;
            }
    printf("correct");
    return 0;
}



C –

NewFolder(1)



题目大意

给定



n

n






n





个字符串,按以下规则输出:

  • 若这个字符串之前每出现过,则输出这个字符串。
  • 若出现过则输出字符串和一个括号,括号里面是之前出现过多少次。



思路

我们用一个



m

a

p

map






ma


p





来存就好了。



代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
string s;
map <string, int> mp;
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        cin >> s;
        cout << s;
        if (mp[s])
            printf("(%d)", mp[s]);
        printf("\n"), mp[s]++;
    }
    return 0;
}



D –

Flipping and Bonus



题目大意





n

n






n





次硬币,如果这次是反面,就将计数器清空,如果这次是正面,就将计数器加一,并且得到



x

i

x_i







x










i





















元。





m

m






m





种额外的奖励,当你的计数器为



c

i

c_i







c










i





















时,你将得到



d

i

d_i







d










i





















的钱。

求你最多能得到多少钱?



思路

考虑



D

P

DP






D


P





我们设



f

i

,

j

f_{i, j}







f











i


,


j






















表示当你

丢完





i

i






i





次硬币时,你的计数器的值为



j

j






j





时最多能得到的钱。

如果



j

0

j\not=0






j



























=








0





,说明这一次丢到的是正面,则



f

i

,

j

=

f

i

1

,

j

1

+

x

i

+

d

j

f_{i, j} = f_{i – 1, j – 1} + x_i + d_j







f











i


,


j





















=









f











i





1


,


j





1





















+









x










i




















+









d










j





















如果



j

=

0

j = 0






j




=








0





,说明这一次丢到的是反面,则



f

i

,

0

=

m

a

x

(

{

f

i

1

,

j

0

j

<

i

}

)

f_{i, 0} = max( \left\{ f_{i – 1, j} | 0 \leq j < i \right\} )







f











i


,


0





















=








ma


x


(



{




f











i





1


,


j



















∣0









j




<




i


}



)







代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, m;
LL f[5005][5005], a[5005], b[5005], ans, maxn;
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &a[i]);
    LL u, v;
    for (int i = 1; i <= m; i++)
        scanf("%lld%lld", &u, &v), b[u] += v;
    f[1][1] = a[1] + b[1];
    for (int i = 2; i <= n; i++) {
        maxn = 0;
        for (int j = 1; j <= i; j++)
            f[i][j] = f[i - 1][j - 1] + a[i] + b[j], maxn = max(f[i - 1][j], maxn);
        f[i][0] = maxn;
    }
    for (int j = 0; j <= n; j++)
        ans = max(ans, f[n][j]);
    printf("%lld", ans);
    return 0;
}



E –

Many Operations



题目大意

有一个变量



x

x






x









n

n






n





种操作,第



i

i






i





中操作有一对数



T

i

T_i







T










i

























A

i

A_i







A










i





















,含义如下:





  • T

    i

    =

    1

    T_i = 1







    T










    i




















    =








    1





    ,则



    x

    =

    x

    &

    A

    i

    x = x \& A_i






    x




    =








    x


    &



    A










    i

























  • T

    i

    =

    2

    T_i = 2







    T










    i




















    =








    2





    ,则



    x

    =

    x

    A

    i

    x = x | A_i






    x




    =








    x






    A










    i

























  • T

    i

    =

    3

    T_i = 3







    T










    i




















    =








    3





    ,则



    x

    =

    x

    x = x






    x




    =








    x





    ^



    A

    i

    A_i







    A










    i





















按如下规则进行操作:

  • 执行操作



    1

    1






    1





    ,输出



    x

    x






    x





  • 执行操作



    1

    1






    1









    2

    2






    2





    ,输出



    x

    x






    x





  • 执行操作



    1

    1






    1









    2

    2






    2









    \cdots
















    n

    n






    n





    ,输出



    x

    x






    x







思路

如果把 看作一个数来处理并不是很好处理,我们把 变为二进制数,一位一位看。

还是考虑



D

P

DP






D


P





,我们设



f

i

,

j

,

0

/

1

f_{i, j, 0/1}







f











i


,


j


,


0/1






















表示执行完操作



1

2

i

1,2,\cdots ,i






1





2















i





,第



i

i






i





位原先是



0

/

1

0/1






0/1





,现在的状态。

于是可以就可以直接按照规则处理。



代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, c, t[200005], a[200005], f[200005][35][2];
int pd(int t, int a, int b) {
    if (t == 1)
        return a & b;
    if (t == 2)
        return a | b;
    return a ^ b;
}
int main() {
    scanf("%d%d", &n, &c);
    for (int i = 1; i <= n; i++)
        scanf("%d%d", &t[i], &a[i]);
    for (int i = 1; i <= 31; i++)
        f[0][i][1] = 1;
    for (int i = 1, op; i <= n; i++) {
        op = a[i];
        for (int j = 1; j <= 30; j++, op = op >> 1) {
            f[i][j][0] = pd(t[i], f[i - 1][j][0], op & 1);
            f[i][j][1] = pd(t[i], f[i - 1][j][1], op & 1);
        }
    }
    int ans = c, last;
    for (int i = 1; i <= n; i++) {
        last = ans, ans = 0;
        for (int j = 1; j <= 30; j++)
            if (f[i][j][(last >> (j - 1)) & 1])
                ans += (1 << (j - 1));
        printf("%d\n", ans);
    }
    return 0;
}



F –

Sorting Color Balls



题目大意





n

n






n





个球,每个球的颜色是



c

i

c_i







c










i





















,球上的数字为



x

i

x_i







x










i





















,我们想要重排这些球使得这些球上的数字从左到右不下降。

我们可以重复以下操作无数次:

  • 选择一个整数



    i

     

    (

    1

    i

    <

    n

    )

    i\ (1 \leq i < n)






    i




    (


    1













    i




    <








    n


    )





    ,交换第



    i

    i






    i





    个和第



    i

    +

    1

    i + 1






    i




    +








    1





    个球,如果这两个球颜色相等,则不花钱,如果这两个球颜色不等,则花一块钱。

求所需要的最小花费。



思路

我们知道在不考虑颜色的情况下所需要的最小交换次数就是逆序对的个数。

我们可以用归并求逆序对,在这时多记录以下前面每个颜色有多少个球,在算的时候就可以直接减去相同颜色的球的逆序对数量。



代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, sum[300005];
LL ans;
struct node {
    int color, number;
} a[300005], b[300005];
void guibin(int l, int r) {
    if (l == r)
        return ;
    int mid = (l + r) / 2;
    guibin(l, mid), guibin(mid + 1, r);
    int i = l, j = mid + 1;
    for (int ii = l; ii <= r; ii++)
        sum[a[ii].color] = 0, b[ii] = a[ii];
    for (int ii = l; ii <= mid; ii++)
        sum[a[ii].color]++;
    int k = i;
    while (i <= mid || j <= r) {
        if (i > mid)
            a[k] = b[j], j++;
        else if (j > r)
            a[k] = b[i], i++;
        else {
            if (b[i].number <= b[j].number)
                a[k] = b[i], sum[b[i].color]--, i++;
            else
                ans = ans + mid - i + 1 - sum[b[j].color], a[k] = b[j], j++;
        }
        k++;
    }
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i].color);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i].number);
    guibin(1, n);
    printf("%lld", ans);
    return 0;
}



版权声明:本文为weixin_46700592原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。