div2 1052 个人补题笔记
链接:Dashboard - Codeforces Round 1052 (Div. 2) - Codeforces
目录
A
B
C
D1+D2
E
A

思路:
统计每个数出现的个数,然后排一下序,设出现次数定为 ,对于元素
,若是
,则就对元素
选
个,若是
,则就对元素
选
个。
根据这个思路,我们 把每个元素出现的次数 按从大到小排序,我们的答案 即是
。
AC代码:
#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代码:
#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';elsecout<<"NO"<<'\n';
}int main(){int t;cin>>t;while(t--){solve();}return 0;
}
C

思路:
朴素想法:
对于 的
,我们要想让 其能二分找到,就要确保
,且对于所有的
,满足
。
对于 的
的
,我们只需要不满足上述条件即可。
在实现上,设 ,若是对于
,存在
,
,说明这种情况肯定不存在。
若是存在方案,我们先使 ,对于
,且
,都满足
时候,我们对
区间的元素翻转存储即可。
AC代码:
#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代码:
#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代码:
#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代码:
#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);elsepoint(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,感觉目前能力达不到,就不补了
