Codeforces Round #493 (Div. 2) (A B C D)

A. Balloons

题目链接:http://codeforces.com/contest/998/problem/A

题目大意:让你把所有的气球分成两份,使得两份的数量不同,随便分。

解题思路:用一个结构体存数量和序号,在根据数量排个序,对于n<=2进行特判下,对于n>2的情况直接输出1和第一个数的序号即可。

AC代码:

struct node
{
    int x;
    int id;
}e[15];

bool cmp(node a, node b)
{
    return a.x < b.x;
}

int main()
{
    int n, a[20];
    while(~scanf("%d", &n)) {
        for(int i = 0; i < n; i ++) {
            scanf("%d", &e[i].x);
            e[i].id = i+1;
        }
        sort(e, e+n, cmp);
        if(n <= 1) {
            printf("-1\n");
            continue;
        }
        if(n == 2) {
            if(e[0].x == e[1].x) printf("-1\n");
            else printf("1\n1\n");
            continue;
        }
        printf("1\n%d\n", e[0].id);
    }
    return 0;
}


B. Cutting

题目链接:http://codeforces.com/contest/998/problem/B

题目大意:给你一个数组,让你把他分成几块,使得每块的奇数个数和偶数个数相同,每次分的花费为分开处两边数字差的绝对值,让你求出在花费不超过B的情况下,能分几下。

解题思路:先求出奇数和偶数个数的前缀和,然后按照前缀和的个数把所有能分的地方的花费都算出来,再排个序,从小到大取,直到大于B,最后输出次数。

AC代码:

int main()
{
    int n, b, a[110], sum1[110], sum2[110];
    while(~scanf("%d%d", &n, &b)) {
        mem0(sum1);
        mem0(sum2);
        for(int i = 1; i <= n; i ++) {
            scanf("%d", &a[i]);
            if(a[i]&1) {
                sum1[i] = sum1[i-1] + 1;
                sum2[i] = sum2[i-1];
            }else {
                sum1[i] = sum1[i-1];
                sum2[i] = sum2[i-1] + 1;
            }

        }
        int cost[110], sum = 0;
        for(int i = 1; i < n; i ++) {
            if(sum1[i] == sum2[i] && sum1[n] - sum1[i] == sum2[n] - sum2[i]) {
                cost[sum ++] = abs(a[i] - a[i+1]);
            }
        }
        sort(cost, cost+sum);
        int ans = 0, s = 0;
        for(int i = 0; i < sum; i ++) {
            s += cost[i];
            if(s <= b) {
                ans ++;
            }else break;
        }
        printf("%d\n", ans);
    }
    return 0;
}


C. Convert to Ones

题目链接:http://codeforces.com/contest/998/problem/C

题目大意:给你一个字符串,有两种操作,花费x把一段字符串反转,花费y把一段连续的0都变成1,求出把该字符串全都变成1的最小花费。

解题思路:先求出0块区域的数量为sum,如果没有反转的操作,那么就需要进行sum次变换的操作,有了反转这个操作,模拟下你会发现,每一次反转操作都只会减少一个0块,所以就相当与一次反转操作可以代替一次变换的操作,这样这个问题就成了一个贪心的问题:当x<y时,就尽量多进行反转,也就是反转sum-1次,最后进行一次变换的操作即可,如果x>=y时,就都进行变换的操作。

AC代码:

int main()
{
    int n;
    LL x, y;
    char str[300010];
    while(~scanf("%d%lld%lld", &n, &x, &y)) {
        scanf("%s", str);
        LL sum = 0;
        for(int i = 0; i < n-1; i ++) {
            if(str[i] == '0' && str[i+1] == '1') sum ++;
        }
        if(str[n-1] == '0') sum ++;
        if(sum == 0) printf("0\n");
        else if(y <= x) {
            printf("%I64d\n", sum*y);
        }else {
           printf("%I64d\n",x*(sum-1) + y);
        }
    }
    return 0;
}


D. Roman Digits

题目链接:http://codeforces.com/contest/998/problem/D

题目大意:给你4个数1 5 10 50,让你挑n个数相加,每个数可以选任意次数,求出能算出多少种不同的数字。

解题思路:%彪神一波,思路数彪神给的:对于这种类型的题,一看数据范围这么大,然后又没有取模的操作,对于每个样例又是出入输出的类型,那么肯定是打表找规律的题,或者可能是什么结论或着公式题之类的,也许这就是题目做多了后,自然又得题感吧,看来还是要多刷题啊!切入正题,我们先dfs跑一边结果,看看有没有什么联系,果然在n<=11时并没有什么联系,但是当n>12时,结果就是一个公差为49的等差数列,那么我们对n<=11的结果进行打表,后面的不断加49即可。

AC代码:

LL a[12] = {
4,
10,
20,
35,
56,
83,
116,
155,
198,
244,
292
};

int main()
{
    LL n;
    while(~scanf("%I64d", &n)) {
        if(n <= 11) {
            printf("%I64d\n", a[n-1]);
        }else {
            printf("%I64d\n", a[10] + 49*(n-11));
        }
    }
    return 0;
}

本场cf感受:终于上分了啊,开黑真的是好玩又刺激,以后还是要多多开黑!

猜你喜欢

转载自blog.csdn.net/i_believe_cwj/article/details/80881449