• 2021牛客寒假算法基础集训营3 题解


    B题

    双指针+贪心,先按照权值排序,对于每个l,找到最近符合条件的r

    注意如果可以不取A,那就别取A

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=1e6+10;
    int cnt,n,k,anum,num,st[N],a[N];
    struct node{
        int id,x,flag;
    }s[N];
    bool cmp(node a,node b){
        return a.x<b.x;
    }
    bool check(){
        if(num==n&&anum<=k)
            return true;
        return false;
    }
    void add(int x){
        if(st[s[x].id]==1&&a[s[x].id]) anum--;//之前存在的那个A没必要取
        st[s[x].id]++;
        if(st[s[x].id]==1)
            num++;
        if(s[x].flag)
            a[s[x].id]=1;
        if(st[s[x].id]==1&&a[s[x].id]) anum++;//只有自己是唯一的并且是A才必须取,不然没有必要取
    }
    void sub(int x){
        if(st[s[x].id]==1&&a[s[x].id]) anum--;
        st[s[x].id]--;
        if(st[s[x].id]==0)
            num--;
        if(s[x].flag)
            a[s[x].id]=0;
        if(st[s[x].id]==1&&a[s[x].id]) anum++;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>k;
        int i,j;
        for(i=1;i<=n;i++){
            for(j=1;j<=5;j++){
                int x;
                cin>>x;
                if(j==1){
                    s[++cnt]={i,x,1};
                }
                else{
                    s[++cnt]={i,x,0};
                }
            }
        }
        sort(s+1,s+1+cnt,cmp);
        int r=1;
        int ans=1e9;
        for(i=1;i<=cnt;i++){
            if(i>1){
                sub(i-1);
            }
            while(r<=cnt&&!check()){
                add(r);
                r++;
            }
            if(check()){
                ans=min(ans,s[r-1].x-s[i].x);
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code

    C题

    暴力做

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=1e6+10;
    int n,k,R;
    int x[N],y[N],r[N];
    int dx[N],dy[N];
    int ans;
    bool check(int i,int j){
        int dis=(x[i]-dx[j])*(x[i]-dx[j])+(y[i]-dy[j])*(y[i]-dy[j]);
        if(dis>(R+r[i])*(R+r[i]))
            return false;
        return true;
    }
    void dfs(int u){
        if(u==k+1){
            int i;
            int cnt=0;
            for(i=1;i<=n;i++){
                int flag=0;
                for(int j=1;j<=k;j++){
                    if(check(i,j)){
                        flag=1;
                    }
                }
                cnt+=flag;
            }
            ans=max(ans,cnt);
            return ;
        }
        int i,j;
        for(i=-7;i<=7;i++){
            for(j=-7;j<=7;j++){
                dx[u]=i,dy[u]=j;
                dfs(u+1);
            }
        }
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>k>>R;
        int i;
        for(i=1;i<=n;i++){
            cin>>x[i]>>y[i]>>r[i];
        }
        dfs(1);
        cout<<ans<<endl;
        return 0;
    }
    View Code

    D题

    签到

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=4e5+10;
    int main(){
        ios::sync_with_stdio(false);
        int n;
        cin>>n;
        int i;
        int d=n;
        int res=0;
        while(d){
            res+=(d%10);
            d/=10;
        }
        for(i=n+1;;i++){
            int sum=0;
            int tmp=i;
            while(tmp){
                sum+=(tmp%10);
                tmp/=10;
            }
            if(res==sum){
                cout<<i<<endl;
                return 0;
            }
        }
        return 0;
    }
    View Code

    E题

    经典套路,维护最近相同数的位置,这里可以借用链表的思想,这样每次只要更改两个位置即可,之后就是线段树查询区间最大值是否大于l

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=1e6+10;
    int n,q,pos[N];
    int a[N],lst[N],nxt[N];
    struct node{
        int l,r;
        int mx;
    }tr[N<<2];
    void pushup(int u){
        tr[u].mx=max(tr[u<<1].mx,tr[u<<1|1].mx);
    }
    void build(int u,int l,int r){
        if(l==r){
            tr[u]={l,r,lst[l]};
        }
        else{
            tr[u]={l,r};
            int mid=l+r>>1;
            build(u<<1,l,mid);
            build(u<<1|1,mid+1,r);
            pushup(u);
        }
    }
    void modify(int u,int l,int x){
        if(tr[u].l==tr[u].r){
            tr[u].mx=x;
            return ;
        }
        int mid=tr[u].l+tr[u].r>>1;
        if(l<=mid){
            modify(u<<1,l,x);
        }
        else{
            modify(u<<1|1,l,x);
        }
        pushup(u);
    }
    int query(int u,int l,int r){
        if(tr[u].l>=l&&tr[u].r<=r){
            return tr[u].mx;
        }
        int mid=tr[u].l+tr[u].r>>1;
        int ans=0;
        if(l<=mid){
            ans=max(ans,query(u<<1,l,r));
        }
        if(r>mid)
            ans=max(ans,query(u<<1|1,l,r));
        return ans;
    }
    int main(){
        ios::sync_with_stdio(false);
        cin>>n>>q;
        int i;
        for(i=1;i<=n;i++){
            cin>>a[i];
            lst[i]=pos[a[i]];
            pos[a[i]]=i;
        }
        for(i=1;i<N;i++){
            pos[i]=n+1;
        }
        for(i=n;i>=1;i--){
            nxt[i]=pos[a[i]];
            pos[a[i]]=i;
        }
        build(1,1,n);
        while(q--){
            int opt;
            cin>>opt;
            if(opt==1){
                int x;
                cin>>x;
                if(nxt[x]!=n+1){
                    modify(1,nxt[x],lst[x]);
                }
                lst[nxt[x]]=lst[x];
                nxt[lst[x]]=nxt[x];
                modify(1,x,0);
            }
            else{
                int l,r;
                cin>>l>>r;
                if(query(1,l,r)>=l){
                    cout<<1<<endl;
                }
                else{
                    cout<<0<<endl;
                }
            }
        }
        return 0;
    }
    View Code

    F题

    贪心题,因为本题每个串都有至少一个#,所以答案要不是0要不是无穷,因为中间的部分可以无限延长。

    那么只要比较前后缀即可

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=1e6+10;
    string s[N];
    string pre[N];
    string suf[N];
    bool cmp(string a,string b){
        return a.size()>b.size();
    }
    bool check1(int x,int y){
        int i;
        for(i=0;i<pre[y].size();i++){
            if(pre[x][i]!=pre[y][i])
                return false;
        }
        return true;
    }
    bool check2(int x,int y){
        int i;
        for(i=0;i<suf[y].size();i++){
            if(suf[x][i]!=suf[y][i])
                return false;
        }
        return true;
    }
    int main(){
        ios::sync_with_stdio(false);
        int n;
        cin>>n;
        int i;
        for(i=1;i<=n;i++){
            cin>>s[i];
        }
        for(i=1;i<=n;i++){
            for(int j=0;j<(int)s[i].size();j++){
                if(s[i][j]!='#'){
                    pre[i]+=s[i][j];
                }
                else{
                    break;
                }
            }
        }
        for(i=1;i<=n;i++){
            for(int j=(int)s[i].size()-1;j>=0;j--){
                if(s[i][j]!='#'){
                    suf[i]+=s[i][j];
                }
                else{
                    break;
                }
            }
        }
        sort(pre+1,pre+n+1,cmp);
        sort(suf+1,suf+1+n,cmp);
        int flag=0;
        for(i=2;i<=n;i++){
            if(!check1(i-1,i)){
                flag=1;
                break;
            }
        }
        for(i=2;i<=n;i++){
            if(flag)
                break;
            if(!check2(i-1,i)){
                flag=1;
                break;
            }
        }
        if(flag){
            cout<<0<<endl;
        }
        else{
            cout<<-1<<endl;
        }
        return 0;
    }
    View Code

    G题

    可以用并查集或者dfs,因为一个集合里面的人取值要相同并且是他们中的最大值

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=2e6+10;
    int n,m;
    int a[N];
    ll f[N],st[N];
    int h[N],ne[N],e[N],idx;
    int cnt;
    void add(int a,int b){
        e[idx]=b,ne[idx]=h[a],h[a]=idx++;
    }
    void dfs(int u,int fa){
        f[u]=a[u];
        st[u]=1;
        int i;
        cnt++;
        for(i=h[u];i!=-1;i=ne[i]){
            int j=e[i];
            if(j==fa||st[j])
                continue;
            dfs(j,u);
            f[u]=max(f[u],f[j]);
        }
    }
    int main(){
        ios::sync_with_stdio(false);
        int i;
        cin>>n>>m;
        memset(h,-1,sizeof h);
        for(i=1;i<=n;i++){
            cin>>a[i];
        }
        for(i=1;i<=m;i++){
            int x,y;
            cin>>x>>y;
            add(x,y);
            add(y,x);
        }
        ll res=0;
        for(i=1;i<=n;i++){
            if(!st[i]){
                cnt=0;
                dfs(i,-1);
                res+=cnt*f[i];
            }
        }
        cout<<res<<endl;
        return 0;
    }
    View Code

    H题

    最多只要修改一次就行了,第一种找到可以拆分的两位数拆分,第二种找到可以合并的一位数合并

    如果这两种都不行,那就不行

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=2e6;
    string s;
    int main(){
        ios::sync_with_stdio(false);
        cin>>s;
        int i;
        int flag=-1;
        for(i=0;i<(int)s.size();i++){
            int fc=s[i]-'a'+1;
            if(fc>10&&fc!=20){
                flag=i;
            }
        }
        if(flag!=-1){
            string res="";
            for(i=0;i<(int)s.size();i++){
                if(i!=flag){
                    res+=s[i];
                }
                else{
                    int fc=s[i]-'a'+1;
                    int d=fc%10;
                    fc/=10;
                    res+='a'+fc-1;
                    res+='a'+d-1;
                }
            }
            cout<<res<<endl;
        }
        else{
            string res="";
            for(i=0;i<(int)s.size()-1;i++){
                int x=s[i]-'a'+1;
                int y=s[i+1]-'a'+1;
                if(x>=10||y>=10)
                    continue;
                if(x*10+y<=26){
                    flag=i;
                    break;
                }
            }
            if(flag!=-1){
                for(i=0;i<(int)s.size();i++){
                    if(i!=flag){
                        res+=s[i];
                    }
                    else{
                        int x=s[i]-'a'+1;
                        int y=s[i+1]-'a'+1;
                        res+='a'+x*10+y-1;
                        i++;
                    }
                }
                cout<<res<<endl;
            }
            else{
                cout<<-1<<endl;
            }
        }
        return 0;
    }
    View Code

    I题

    贪心,只要能出现合并的就合并,这样一定不劣,因为每次多一个相同只会最多多一个,而我们合并也多了一个

    所以只要用map记录最近的与我相同的位置,一旦合并成功,就把之前的map信息删除

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=2e6+10;
    int a[N];
    map<int,int> m1;
    int main(){
        ios::sync_with_stdio(false);
        int i;
        int n;
        cin>>n;
        for(i=1;i<=n;i++)
            cin>>a[i];
        int ans=0;
        for(i=1;i<=n;i++){
            if(m1[a[i]]){
                m1.clear();
                ans++;
                m1[a[i]]=1;
            }
            else{
                m1[a[i]]++;
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code

    J题

    思维博弈,注意特判1

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=2e6;
    int a[N];
    int main(){
        ios::sync_with_stdio(false);
        int n;
        int i;
        cin>>n;
        for(i=1;i<=n;i++)
            cin>>a[i];
        if(n==1&&(a[1]%2==1)){
            cout<<"NiuNiu"<<endl;
            return 0;
        }
        if(n%2==0){
            int cnt=0;
            for(i=1;i<=n;i++){
                if(a[i]%2==0){
                    cnt++;
                }
            }
            if(cnt<=1){
                cout<<"NiuNiu"<<endl;
                return 0;
            }
        }
        cout<<"NiuMei"<<endl;
        return 0;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    Xubuntu 计划从 19.04 版本开始停止提供 32 位安装镜像(XDE/LXQt的 Lubuntu 成为了目前唯一仍然提供 32 位安装镜像的 Ubuntu 桌面发行版)
    Go 语言的下一个大版本:Go 2.0 被安排上了(全面兼容1.X,改进错误处理和泛型这两大主题)
    Error Handling Functions(微软对于出错的情况下提供的所有函数,比如SetThreadErrorMode,SetErrorMode,SetLastErrorEx,FatalAppExit,CaptureStackbackTrace)
    Windows10、ARM开发板、VMware虚拟机同时连接Internet
    压力测试命令行工具SuperBenchmarker
    wireshark 抓包过滤器
    古典、SOA、传统、K8S、ServiceMesh
    了解ASP.NET Core框架的本质
    多线程实现报表的高效导出
    kafka日志同步至elasticsearch和kibana展示
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/14382250.html
Copyright © 2020-2023  润新知