比赛题解

codeforces

A. Anastasia and pebbles

题意:
给你n种小石块,数目确定,你每次每只手只能拿k个小石块,每只手只能拿一种小石块,问多少次拿完。

思路:
贪心。
排序后从最少的开始取。我们设当前你要取的石头堆的剩余石头为cur,每次拿取有如下几种情况:

  • cur<=k 全部取走,并让另一只手去重新讨论下一堆石头
  • k < cur < 2*k 两只手全部取走 所取石头堆往后移
  • cur>2*k 两只手全部取走 当前讨论石头堆不变
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iterator>
#include <queue>
#include <set>
#include <string>

#define ll long long

using namespace std;
const double eps = 1e-6;
const int maxn = 100010;
const int inf = 0x3f3f3f3f;

int n, m;
int arr[maxn];

int main()
{
    while (scanf("%d %d", &n, &m) != EOF) {
        for (int i = 0; i < n; i++)
            scanf("%d", arr + i);
        sort(arr,arr+n);
        int idx=0,ans=0;
        while(idx<n)
        {
            ans++;
            if(arr[idx]<=m){
                idx++;
                if(idx>=n)
                    break;
                if(arr[idx]<=m)
                    idx++;
                else
                    arr[idx]-=m;
            }
            else {
                arr[idx]-=m;
                if(arr[idx]<=m)
                    idx++;
                else
                    arr[idx]-=m;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
B. Masha and geometric depression

题意:
给你一个等比数列和数组,并给你一个上界,要你要上界之下 输出 不属于这个数组的 等比数列的所有数

思路:
题目不难,就是情况有点多,不知道怎么快速,清晰的表达
我这里用了两个set group 和 vis ,group存数组,vis存 已遍历的 等比数列的项
如果不考虑特殊情况的话,就只是两个集合之间的运算,这就不多说了。这里说一下我对特殊情况的考虑和处理。
特殊情况分为:

  • b=0 q=?
  • b=? q=0
  • b=? q=-1

但无论哪种情况,都会出现重复的元素。如果出现重复的元素,如果group内存在这个重复元素,就直接输出记录结果,否则输出inf。
但是第三种 -1 的情况会有点特殊,它可以在-b 和 b 之间不停跳转,这时候就得查找 -b 是否也在group内,如果存在,就输出记录结果,不存在就输出inf。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iterator>
#include <queue>
#include <set>
#include <string>

#define ll long long

using namespace std;
const double eps = 1e-6;
const int maxn = 100010;
const int inf = 0x3f3f3f3f;

ll b, q, l, m;
set<int> group;
set<int> vis;

int main()
{
    int tmp;
    while (scanf("%lld %lld %lld %lld", &b, &q, &l, &m) != EOF) {
        group.clear();
        vis.clear();
        for (int i = 0; i < m; i++) {
            scanf("%d", &tmp);
            group.insert(tmp);
        }
        int ans = 0;
        bool flag = false;
        while (abs(b) <= l) {
            if (vis.find(b) != vis.end()) {
                if (group.find(b) != group.end() && (q != -1 || group.find(-b) != group.end()))
                    printf("%d\n", ans);
                else
                    puts("inf");
                flag = true;
                break;
            }
            vis.insert(b);
            if (group.find(b) == group.end())
                ans++;
            b *= q;
        }
        if (!flag)
            printf("%d\n", ans);
    }
    return 0;
}
C. Functions again

题意:
给你一个数组,如下公式,让你求最大的 f(l,r)
公式

思路:
把数组内所有数都转化一下 再求连续最大和即可(比B题简单多了

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <stack>
#include <vector>

using namespace std;

long long arr[100100];

long long MaxSubArray(long long a[], long long len)
{
    long long maxsum, maxhere;
    maxsum = maxhere = a[0]; 
    for (int i = 1; i < len; i++) {
        if (maxhere <= 0)
            maxhere = a[i]; 
        else
            maxhere += a[i]; 
        if (maxhere > maxsum) {
            maxsum = maxhere; 
        }
    }
    return maxsum;
}
int main()
{
    int n;
    while (scanf("%d", &n) != EOF) {
        for (int i = 0; i < n; i++)
            scanf("%lld", arr + i);
        int key = 1;
        for (int i = 0; i < n - 1; i++) {
            arr[i] = abs(arr[i] - arr[i + 1]) * key;
            key *= -1;
        }
        long long ans = MaxSubArray(arr,n-1);
        for(int i=0;i<n-1;i++)
            arr[i]*=-1;
        printf("%lld\n",max(ans,MaxSubArray(arr, n - 1)));
    }
    return 0;
}
D. Weird journey

note:这题我自己也搞不明白,最好先别看,大神只给了我代码,我现在也理解不了

题意:
给你一个n,表示点数,m,表示边数目,m条边,构建成无向图,要你求出满足如下要求的路径数目。
任意起点,终点,满足路径上,有两条边只走过一次,其他m-2走过两次。
起点和终点不同即是路径不同,但如果起点0=终点1 终点0=起点1 则0 ,1 视为同一路径

思路:
无( ~~玛德,只给我代码,白白看了2个小时还看不懂。~~

#include <bits/stdc++.h>

using namespace std;

typedef long long int64;

const int maxn = 1000000 + 10;
int root[maxn];

int findRoot(int a)
{
    if (root[a] == a)
        return a;
    return root[a] = findRoot(root[a]);
}

bool join(int a, int b)
{
    a = findRoot(a);
    b = findRoot(b);
    if (a == b)
        return false;
    root[b] = a;
    return true;
}

int64 dg[maxn];
bool seen[maxn];

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    int64 n, m;
    cin >> n >> m;
    int tot = 0;    //出现的点数
    int cmp = n;    //点集数

    for (int i = 0; i < n; ++i) {
        root[i] = i;
    }

    int64 loop = 0;  //自环数
    int64 ans = 0;

    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        --u, --v;

        if (u == v) {
            ans += m - ++loop; //不是很懂这个地方
            if (!seen[u])
                tot++;
            seen[u] = true;
            continue;
        }

        if (!seen[u])
            tot++;
        dg[u]++;
        seen[u] = true;
        if (!seen[v])
            tot++;
        seen[v] = true;
        dg[v]++;
        if (join(u, v))
            cmp--;      
    }

    if (cmp != n - tot + 1) {
        cout << 0 << endl;
        return 0;
    }

    for (int i = 0; i < n; ++i)
        ans += dg[i] * (dg[i] - 1) / 2;

    cout << ans << endl;

    return 0;
}

如果有看懂的朋友记得跟我说一声……

E. The Great Mixing

(暂缺)

发表评论

电子邮件地址不会被公开。 必填项已用*标注