返回顶部

Educational Codeforces Round 87 (Rated for Div. 2)【ABC1C2D】(题解)

涵盖知识点:解析几何、树状数组

比赛链接:传送门

A - Alarm Clock

题意: 一天要睡够\(a\)分钟,但是\(b\)分钟后有一个闹钟会使其醒来,他会把闹钟推迟到\(c\)分钟之后,然后花费\(d\)小时再次入睡。问要多久能够睡够。
题解: 模拟推公式
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    int t;cin>>t;
    while(t--){
        ll a,b,c,d;
        cin>>a>>b>>c>>d;
        if(b>=a){
            cout<<b<<"\n";
            continue;
        }
        if(d>=c){
            cout<<-1<<"\n";
            continue;
        }
        cout<<(a-b+c-d-1)/(c-d)*c+b<<"\n";
    }
    return 0;
}

B - Ternary String

题意: 给定的串仅含有\(1,2,3\)。问最短的字串使得同时存在这三种字符。
题解: 顺序扫描,在线更新。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
int vis[3];
string s;
int main(){
    int t;cin>>t;
    while(t--){
        memset(vis,0,sizeof vis);
        cin>>s;
        int ans=s.length()+1,n=0;
        for(int i=0;i<s.length();i++){
            while(n<s.length()&&(!vis[0]||!vis[1]||!vis[2])){
                vis[s[n]-'1']++;
                n++;
            }
            if(vis[0]&&vis[1]&&vis[2])ans=min(ans,n-i);
            vis[s[i]-'1']--;
        }
        if(ans>s.length())cout<<"0\n";
        else cout<<ans<<"\n";
    }
    return 0;
}

C1 - Simple Polygon Embedding

题意: \(n\)为偶数,\(2n\)个长度为\(1\)的线段构成一个正\(2n\)边形。问最小的正方形使得能够包裹住这个多边形。
题解: \(2n\)可被\(4\)整除。选两组对边与正方形重合显然最小。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const double pi=acos(-1);
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        printf("%.9lf\n",1/tan(pi/(n*2)));
    }
    return 0;
}

C2 - Not So Simple Polygon Embedding

题意: n$为奇数,\(2n\)个长度为\(1\)的线段构成一个正\(2n\)边形。问最小的正方形使得能够包裹住这个多边形。
题解: 设偏转角为\(x\),外接圆半径为\(l\),所求正方形的半边长为\(r\),可以得出\(r=l\times \cos x\),求导获得单调性\(r'=-\sin x\)。在\([0,\pi]\)导数小于0,所以长度单调递减。又根据对称性可以得到取到的最小值应该在\(x=\frac{\pi}{4n}\)时取到。

Accept Code:

#include <bits/stdc++.h>
using namespace std;
const double pi=acos(-1);
int main(){
    int t;cin>>t;
    while(t--){
        int n;
        cin>>n;
        double a=pi/(n*2);
        double r=1/sin(a);
        a/=2;
        printf("%.9lf\n",r*cos(a));
    }
    return 0;
}

D - Multiset

题意: 多重集合,初始化后可以选择增加新数字或者删除某个位置的数字。求操作完成后集合内剩下的数字。
题解: 树状数组维护每个数字的个数。通过前缀和判断该位置是哪个数字。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int c[maxn],n,q;
inline int lowbit(int x){return x&(-x);}
void add(int x){
    while(x<=n){
        c[x]++;
        x+=lowbit(x);
    }
}
void del(int x){
    while(x<=n){
        c[x]--;
        x+=lowbit(x);
    }
}
int query(int x){
    int res=0;
    while(x){
        res+=c[x];
        x-=lowbit(x);
    }
    return res;
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>q;
    for(int i=0,x;i<n;i++)cin>>x,add(x);
    for(int i=0,x;i<q;i++){
        cin>>x;
        if(x>0) { add(x); continue;}
        x=-x;
        int l=1,r=n,ans;
        while(l<=r){
            int mid=(l+r)/2;
            if(query(mid)>=x)ans=mid,r=mid-1;
            else l=mid+1;
        }
        del(ans);
    }
    for(int i=1;i<=n;i++){
        if(query(i)){
            cout<<i<<"\n";
            return 0;
        }
    }
    cout<<"0\n";
    return 0;
}
posted @ 2020-05-18 17:38  Charles1999  阅读(182)  评论(0编辑  收藏  举报