链接:Dashboard - Codeforces Round 1052 (Div. 2) - Codeforces
目录
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,感觉目前能力达不到,就不补了