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

 

posted @ 2021-02-06 17:38  朝暮不思  阅读(75)  评论(0编辑  收藏  举报