div2 1052 个人补题笔记

链接:Dashboard - Codeforces Round 1052 (Div. 2) - Codeforces

目录

A

B

C

D1+D2

E


A

思路:

统计每个数出现的个数,然后排一下序,设出现次数定为 ,对于元素 ,若是 ,则就对元素 个,若是 ,则就对元素 个。

根据这个思路,我们 把每个元素出现的次数 按从大到小排序,我们的答案 即是

AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=110;
int cnt[N];
bool cmp(int a,int b){
    return a>b;
}
void solve(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
        cnt[i]=0;
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        cnt[x]++;
    }
    int ans=0;
    sort(cnt+1,cnt+n+1,cmp);
    for(int i=1;i<=n;i++){
        ans=max(ans,cnt[i]*i);
    }
    cout<<ans<<'\n';
}

int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

B

思路:

对于可能构造的方案,首先,所有 都选择是一种方案,然后 所有 中删除一个 也是一种方案,这样我们就有了 种方案,其他方案成立的前提是以上 种方案是否至少有 种方案成立,因此只需看这 种方案即可。

我们可以开个 数组 ,然后我们把每一组的元素都存起来,设 为元素 出现的次数。

我们看少了一组方案的元素后,对于任意一个元素 ,是否出现 的情况,如果没有出现即可说明这种方案是成立的,我们只需要有 种这种方案即可说明存在。

AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
int cnt[N];
int n,m;
void solve(){
    cin>>n>>m;
    for(int i=1;i<=m;i++)
        cnt[i]=0;
    vector<vector<int> >cun(n+1);
    for(int i=1;i<=n;i++){
        int s;
        cin>>s;
        for(int j=1;j<=s;j++){
            int x;
            cin>>x;
            cnt[x]++;
            cun[i].push_back(x);
        }
    }
    int sum=0;
    for(int i=1;i<=n;i++){
        bool st=false;
        for(auto c:cun[i]){
            if(cnt[c]==1){
                st=true;
                break;
            }
        }
        if(!st)
            sum++;
    }
    for(int i=1;i<=m;i++)
        if(cnt[i]==0)
            sum=0;
    if(sum>=2)
        cout<<"YES"<<'\n';
    else
        cout<<"NO"<<'\n';
}

int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

C

思路:

朴素想法:

对于 ,我们要想让 其能二分找到,就要确保 ,且对于所有的 ,满足

对于 ,我们只需要不满足上述条件即可。

在实现上,设 ,若是对于 ,存在 ,说明这种情况肯定不存在。

若是存在方案,我们先使 ,对于 ,且 ,都满足 时候,我们对 区间的元素翻转存储即可。

AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
int n;
int a[N];


void solve(){
    string s;
    cin>>n;
    cin>>s;
    s="1"+s+"1";
    for(int i=1;i<=n;i++){
        if(s[i]=='0'&&s[i-1]=='1'&&s[i+1]=='1'){
            cout<<"NO"<<'\n';
            return ;
        }
    }
    cout<<"YES"<<'\n';
    int id=1;
    for(int i=1;i<=n+1;i++){
        if(s[i]=='1'){
            a[i]=i;
            int x=i-1;
            for(int j=id;j<i;j++){
                a[j]=x--;
            }            
            id=i+1;
        }
    }
    for(int i=1;i<=n;i++){
        cout<<a[i]<<' ';
    }
    cout<<'\n';
}

int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

D1+D2

思路:

对于 而言,在 中对于每一个数 ,必然存在唯一一个数 ,让最终解最大。

假设一个数的二进制为 ,那么和其匹配的必然是 ,我们可以从大到小枚举,对于每个形如 这类未配对的数,我们找形如 的与其配对。

AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
typedef long long ll;
ll a[N];
bool st[N];
int l,r;

void solve(){
    cin>>l>>r;
    for(int i=0;i<=r;i++)
        st[i]=false;
    for(int i=r;i>=0;i--){
        if(st[i])
            continue;
        int x=0;
        bool k=false;
        for(int j=20;j>=0;j--){
            int c=1<<j;
            if((i&c)){
                k=true;
                continue;
            }else if(k)
                x+=c;
        }
        st[x]=st[i]=true;
        a[i]=x;
        a[x]=i;
    }
    ll ans=0;
    for(int i=0;i<=r;i++)
        ans+=(ll)i|a[i];
    cout<<ans<<'\n';
    for(int i=0;i<=r;i++)
        cout<<a[i]<<' ';
    cout<<'\n';
}

int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

对于 而言,可以发现, 匹配时是最好的, 是最优的

根据这个基本想法,我们可以每次对 先按二进制拆分,然后我们要找满足如下条件的最大的

,然后我们把 都提出来设为 ,设

我们划分为 两个区间,依次按照 匹配 匹配 的思路完成匹配,最后有以下三种情况:

(1),设 没有匹配,则把 再按照上述递归处理即可。

(2),设 没有匹配,则把 再按照上述递归处理即可。

(3),说明匹配完成,结束递归即可。

AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+100;
typedef long long ll;
map<ll,ll>a;
ll l,r;

int cal(int x,int cnt){
    ll c=0;
    for(ll i=30;i>=0;i--){
        ll r=(ll)1<<i;
        if(x&r){
            cnt--;
            c+=r;
        }
        if(cnt==0)
            return c;
    }
    return c;
}

void check(int l,int r,int d){
    if(l>=r) {
        if(l==r)
            a[l]=l;
        return ;
    }
    while(cal(l,d)==cal(r,d))
        d++;
    ll k=cal(r,d);
    ll i=k,j=k-1;    
    for(;i<=r&&j>=l;i++,j--){
        a[i]=j;
        a[j]=i;
    }
    if(i<=r)
        check(i,r,d);
    else 
        check(l,j,d);
}   

void solve(){
    cin>>l>>r;
    check(l,r,1);
    ll ans=0;
    for(int i=l;i<=r;i++)
        ans+=(i|a[i]);
    cout<<ans<<'\n';
    for(int i=l;i<=r;i++)
        cout<<a[i]<<' ';
    cout<<'\n';
}

int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

E

思路:

对于区间 ,假设 在区间 中没有出现过该元素,我们定义 中满足条件的 的个数。

我们可以证明的是, 是必然的,因为对于 而言, 越小, 越大,而 是最小的

假设 ,且对于任意的 ,则 就是右区间为 ,且满足要求的情况下最大的

所以,对于每个定值右区间 ,我们需要维护,去找每一个可能的 对应的

我们可以使用线段树来维护,具体流程:

(1)对于每个定值右区间 ,对于 而言,我们相当于让

(2)而对于 这个点而言,由于到 时候 是不满足要求的,所以要把这时候的

然后每一次查询输出最大的

AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+100;
typedef long long ll;
ll tr[N],lz[N];
int n;

void build(int l,int r,int u){
    tr[u]=lz[u]=0;
    if(l==r)
        return ;
    int mid=(l+r)/2;
    build(l,mid,2*u+1);
    build(mid+1,r,2*u+2);
}

void modify(int L,int R,int l,int r,int u){
    if(L<=l&&r<=R){
        tr[u]++;
        lz[u]++;
        return ;
    }
    int mid=(l+r)/2;
    if(mid>=L)
        modify(L,R,l,mid,2*u+1);
    if(mid<R)
        modify(L,R,mid+1,r,2*u+2);
    tr[u]=max(tr[2*u+1],tr[2*u+2])+lz[u];
}

void point(int x,int l,int r,int u,int val){
    if(l==r){
        tr[u]=-val;
        return ;
    }
    int mid=(l+r)/2;
    val+=lz[u];
    if(x<=mid)
        point(x,l,mid,2*u+1,val);
    else
        point(x,mid+1,r,2*u+2,val);
    tr[u]=max(tr[2*u+1],tr[2*u+2])+lz[u];
}

void solve(){
    cin>>n;
    build(0,n,0);
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        modify(0,x,0,n,0);
        point(x,0,n,0,0);
        cout<<tr[0]<<' ';
    }
    cout<<'\n';
}


int main(){
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

至于之后2900的F,感觉目前能力达不到,就不补了

相关推荐
蒙奇D索大2 小时前
【计算机网络】[特殊字符] 408高频考点 | 数据链路层组帧:从字符计数到违规编码,一文学透四大实现方法
网络·笔记·学习·计算机网络·考研
njsgcs3 小时前
tekla 使用笔记 切管 分割指定长度的管
笔记·tekla
蒙奇D索大5 小时前
【算法】 递归实战应用:从暴力迭代到快速幂的优化之路
笔记·考研·算法·改行学it
('-')5 小时前
《从根上理解MySQL》第一章学习笔记
笔记·学习·mysql
d111111111d5 小时前
STM32外设学习-串口发送数据-接收数据(笔记)
笔记·stm32·学习
昊喵喵博士7 小时前
直接用 JavaScript 给输入框赋值,Vue 页面input只是纯展示 并 没有触发 vue 的v-model 赋值
笔记
卡提西亚8 小时前
C++笔记-26-类模板
c++·笔记
yaocheng的ai分身9 小时前
停止过度思考 Obsidian:一份真正有效的初学者指南
笔记