Codeforces Round #388 (Div. 2) A,B,C,D 题解

【A】水题,分奇偶贪心即可。复杂度O(n)

int main()
{
    int n;
    cin>>n;
    if(n%2==0)
    {
        cout<<n/2<<endl;
        for(int i = 0; i < n/2; i++) cout<<"2"<<" ";
    }
    else{
        cout<<n/2<<endl;
        for(int i = 0; i < n/2-1; i++) cout<<"2"<<" ";
        cout<<"3"<<endl;
    }
}

【B】给定3个点,要求另外的点使得这4个点构成平行四边形,暴力枚举计算即可,复杂度O(1)

struct point{
    int x, y;
    bool operator<(const point &rhs)const{
        if(x == rhs.x) return y > rhs.y;
        return x < rhs.x;
    }
}p[3], ans[10];
int main()
{
    int cnt = 0;
    cin>>p[0].x>>p[0].y>>p[1].x>>p[1].y>>p[2].x>>p[2].y;
    for(int i = 0; i < 3; i++){
        for(int j = i + 1; j < 3; j++){
            int t = 3 - i - j;
            int x = p[i].x - p[j].x;
            int y = p[i].y - p[j].y;
            ans[cnt++] = point{x + p[t].x , y + p[t].y};
            ans[cnt++] = point{p[t].x - x, p[t].y - y};
        }
    }
    sort(ans, ans+cnt);
    int t = 1;
    for(int i = 1; i < cnt; i++){
        if(ans[i].x != ans[i-1].x || ans[i].y != ans[i-1].y){
            t++;
        }
    }
    cout<<t<<endl;
    cout<<ans[0].x<<" "<<ans[0].y<<endl;
    for(int i = 1; i < cnt; i++){
        if(ans[i].x != ans[i-1].x || ans[i].y != ans[i-1].y){
            cout<<ans[i].x << " "<<ans[i].y<<endl;
        }
    }
}

【C】给了个由DR组成的字符串,从头开始,每个字母可以干掉和他不同的另外一个字母。到了末尾之后,他又可以到开头,问最后剩下的是哪种字母?贪心+模拟,用set来维护剩余的'D'和'R',然后砍的时候去set里面二分位置,注意细节,没注意找到end之后要变成begin,最后fst了。。复杂度 O(nlogn)


char s[200010];
int vis[200010];
set<int>s1, s2;
map <int, bool> mp;
int main()
{
    int n;
    cin>>n>>s;
    for(int i = 0; i < n; i++){
        if(s[i] == 'D') s1.insert(i), mp[i] = 0;
        else s2.insert(i), mp[i] = 1;
    }
    memset(vis, true, sizeof(vis));
    while(1)
    {
        if(s1.empty() || s2.empty()){
            break;
        }
        for(auto & i : mp){
            if(s1.empty() || s2.empty()) break;
            if(i.second == 0){
                auto it = s2.lower_bound(i.first);
                if(it == s2.end()) it = s2.begin();
                mp.erase(*it);
                s2.erase(it);
            }
            else{
                auto it = s1.lower_bound(i.first);
                if(it == s1.end()) it = s1.begin();
                mp.erase(*it);
                s1.erase(it);
            }
        }
    }
    if(s1.empty()){
        printf("R\n");
    }
    else{
        printf("D\n");
    }
}

【D】有许多人参加拍卖,问当假定某些人不参加的时候剩余的人当中谁是最终的赢家,输出他的编号和最终竞价? 解题思路摘抄自 : 点击打开链接 应该是把每个人的所有竞价用set(其他骚东西也行)存储下来,再开一个map将每个人的最高竞价也存下来,然后将该去掉的人去掉后找到那个竞价最高的,这时候切记千万不要直接输出(原因见上面下划线),应该再找到竞价第二高的人的最高竞价x,然后在竞价最高的人的所有竞价里找到一个恰好大于x的一个值。这里还有一个特判,加入将该去的人都去掉以后只剩下一个人了,那么久不会存在竞价第二高的人了,此时应直接输出竞价最高的人的所有竞价中最小的那一个(即他的第一次竞价)


map <int, int> p; //p记录最大
map <int, int > q; //q记录维护的集合
set <int> num[200010]; //记录第一次出现
int b[200010];
int main()
{
    int n, qqq;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        int x, y;
        scanf("%d%d", &x,&y);
        num[x].insert(y);
        p[x] = max(p[x], y);
    }
    for(int i = 1; i <= n; i++)
    {
        if(p[i])
        {
            q.insert(MP(p[i], i));
        }
    }
    scanf("%d", &qqq);
    for(int i = 1; i <= qqq; i++)
    {
        int k;
        scanf("%d", &k);
        for(int j = 1; j <= k; j++){
            scanf("%d", &b[j]);
            if(p[b[j]]){
                q.erase(p[b[j]]);
            }
        }
        int sz = q.size();
        if(sz == 0){
            printf("0 0\n");
        }
        else if(sz == 1){
            auto it = q.end();
            it--;
            printf("%d %d\n", it->second, *num[it->second].begin());
        }
        else{
            auto it = q.end();
            it--;
            int t1 = it -> second;
            it--;
            int t2 = it -> first;
            auto itt = num[t1].upper_bound(t2);
            printf("%d %d\n", t1, *itt);
        }
        for(int j = 1; j <= k; j++){
            if(p[b[j]]){
                q.insert(MP(p[b[j]], b[j]));
            }
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值