CF-558:部分题目总结

题目链接:http://codeforces.com/contest/1163

A .Eating Soup

sol:在n / 2、n - m、m三个数中取最小值,结果受这三个值限制。但是m == 0的情况需要特判

  • 思维
    #include "bits/stdc++.h"
    using namespace std;
    int main() {
        int n, m;
        scanf("%d%d", &n, &m);
        if (m == 0) {puts("1"); return 0;}
        printf("%d\n", min(n >> 1, min(n - m, m)));
        return 0;
    } 
    View Code

    没有考虑n - m导致了一发wa,而且想了一定时间。好像有点生疏了,哎。

B1 .Cat Party (Easy Edition)

sol:在这一题中u[i]的范围只有10,可以用循环来尝试删除,并判断删除后可否满足题目要求,然后记录;

  • 暴力
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1e5 + 5;
    int cnt[MAXN];
    int ans, n, k;
    bool check() {
        int k = -1;
        for (int i = 1; i <= 10; i++) {
            if (cnt[i]) {
                if (k == -1) k = cnt[i];
                else if (k != cnt[i]) return false;
            }
        }
        return true;
    }
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &k);
            cnt[k]++;
            /*
             做B2的时候意识到每次删除的要么是只出现一次的数要么是出现次数最多的数 
             所以这个循环可以改成找最大值,然后检查一下最大值和1就行了 
            */ 
            for (int j = 1; j <= 10; j++) {
                if (cnt[j]) {
                    cnt[j]--;
                    if (check()) ans = i;
                    cnt[j]++;
                }
            }
        }
        printf("%d\n", ans);
        return 0;
    }
    View Code

     

B2 .Cat Party (Hard Edition)

sol:每次删除的数要么是只出现一次的,或者是出现次数最多的。但是暴力找要超时,所以我就用STL里的multiset来了一波优化后的暴力。把思维题做成了暴力;

  • 带优化暴力
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1e5 + 5;
    multiset<int> st;
    multiset<int>::iterator it;
    int cnt[MAXN];
    int ans, n, k;
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &k);
            if (cnt[k]) {
                it = st.find(cnt[k]);
                st.erase(it);
            }
            cnt[k]++;
            st.insert(cnt[k]);
            // 特判只有一种数字 
            if (st.size() == 1) {
                ans = i;
                continue;
            } 
            if (*st.begin() == 1) {
                st.erase(st.begin());
                if (*st.begin() == *(--st.end())) ans = i;
                st.insert(1);
            }
            it = --st.end();
            k = *it;
            st.erase(it);
            if (*st.begin() == k - 1 && *(--st.end()) == k - 1) ans = i;
            st.insert(k);
        }
        printf("%d\n", ans);
        return 0;
    }
    View Code

    思维果然跟不上队友,只能靠STL这种道具。队友想到了正解

sol:这题的正解是数据结构,用两个数组a和b,a[i]表示数字i出现几次,b[i]表示出现i次的数有几个

  • 数据结构
    #include "bits/stdc++.h"
    using namespace std;
    const int MAXN = 1e5 + 5;
    int a[MAXN], b[MAXN];
    int n, k, mx, ans;
    int main() {
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &k);
            b[a[k]]--;
            a[k]++;
            b[a[k]]++;
            mx = max(mx, a[k]);
            if (b[1] == i) ans = i;
            else if (b[i] == 1) ans = i;
            else if (b[1] == 1 && b[mx] * mx == i - 1) ans = i;
            else if ((b[mx - 1] + 1) * (mx - 1) == i - 1) ans = i;
        }
        printf("%d\n", ans);
        return 0;
    }
    View Code

     

  • 别人同思路的代码
    #include <bits/stdc++.h>
    
    using namespace std;
    int64_t n,x,ans;
    map<int,int>a,b;
    int main()
    {
        cin>>n;
        ans=1;
        for(int i=1;i<=n;i++)
        {
            cin>>x;
            a[x]++;b[a[x]]++;
            if(a[x]*b[a[x]]==i&&i!=n) ans=i+1;
            if(a[x]*b[a[x]]==i-1) ans=i;
        }
        cout<<ans;
    }
    View Code

    看到一份别人的思路差不多的代码,但是他用了map代码很整洁,贴一下。

C .Power Transmission

sol:将所有点两两配对,两个点确定一条直线,求出直线方程一般式的a、b、c。将a和b约分后去重。对于每条边,加一次和自己斜率不同的边的个数就行了。

  • 几何
    #include "bits/stdc++.h"
    using namespace std;
    typedef pair<int, int> PII;
    typedef long long LL;
    const int MAXN = 1005;
    PII p[MAXN];
    map<PII, set<LL> > mp;
    LL tot, ans;
    int main() {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++)
            scanf("%d%d", &p[i].first, &p[i].second);
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j < i; j++) {
                int x1 = p[i].first, y1 = p[i].second;
                int x2 = p[j].first, y2 = p[j].second;
                int a = y2 - y1, b = x1 - x2, g = __gcd(a, b);
                a /= g, b /= g;
                LL c = 0 - a * 1LL * x2 - b * 1LL * y2;
                if (mp[{a, b}].count(c) == 0) {
                    mp[{a, b}].insert(c);
                    tot++;
                    ans += tot - mp[{a, b}].size();
                }
            }
        }
        printf("%lld\n", ans);
        return 0;
    }
    View Code

    以前学的直线方程什么的都忘的差不多了,看出题人的标程里面求c的过程还以为是hash。花了好久才搞明白,提交了十几发。也算收获不小。

转载于:https://www.cnblogs.com/Angel-Demon/p/10846796.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值