1. 程式人生 > >Codeforces Round #493 (Div. 2) (A B C D)

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

A. Balloons

題目大意:讓你把所有的氣球分成兩份,使得兩份的數量不同,隨便分。

解題思路:用一個結構體存數量和序號,在根據數量排個序,對於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

題目大意:給你一個數組,讓你把他分成幾塊,使得每塊的奇數個數和偶數個數相同,每次分的花費為分開處兩邊數字差的絕對值,讓你求出在花費不超過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

題目大意:給你一個字串,有兩種操作,花費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

題目大意:給你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感受:終於上分了啊,開黑真的是好玩又刺激,以後還是要多多開黑!