A

模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
const int N=2e5+10;

void solve(){
int cnt[27]={0};
int n;cin>>n;
string s;cin>>s;
for(int i=0;i<s.size();i++){
cnt[s[i]-'A'+1]++;
}
int ans=0;
for(int i=1;i<=26;i++){{
if(cnt[i]>=i)ans++;
}

}
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}

B

构造一个先升后降的序列即可,也就是先从n-k输出到n再输出k-1到1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
const int N=2e5+10;

void solve(){
int n,k;cin>>n>>k;
for(int i=n-k;i<=n;i++){
cout<<i<<' ';
}
for(int i=n-k-1;i>=1;i--)
{
cout<<i<<' ';
}
cout<<'\n';

}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}

C

当我们需要选出k个任务的时候,就是枚举i从1-k分别作为选择a数组和b数组的数目,a数组用一个前缀和维护,b只用记录最大值

需要注意的是枚举的时候k可能大于n,分类讨论或者取min都可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
const int N=2e5+10;

void solve(){
i64 n,k;cin>>n>>k;
int a[N]={0},b[N]={0};
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
i64 ans=0,sum=0;
int mx=0;
for(int i=1;(i<=n)&&(i<=k);i++){
sum+=a[i];
mx=max(b[i],mx);
ans=max(ans,sum+1ll*mx*(k-i));
}
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}

D

我用的是结构体,然后排序选前三个讨论,相同就跳过,因为三天最多只会选到某个的第三大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
const int N=2e5+10;
void solve(){
int n;cin>>n;
vector<pair<int,int>>v1;
vector<pair<int,int>>v2;
vector<pair<int,int>>v3;
for(int i=1;i<=n;i++){
int x;cin>>x;
v1.push_back(make_pair(x,i));
}
for(int i=1;i<=n;i++){
int x;cin>>x;
v2.push_back(make_pair(x,i));
}
for(int i=1;i<=n;i++){
int x;cin>>x;
v3.push_back(make_pair(x,i));
}
int ans=0;
sort(v1.begin(),v1.end());
sort(v2.begin(),v2.end());
sort(v3.begin(),v3.end());
for(int i=n-1;i>=n-3;i--){
for(int j=n-1;j>=n-3;j--){
for(int k=n-1;k>=n-3;k--){
if(v2[j].second==v3[k].second||v1[i].second==v2[j].second||v1[i].second==v3[k].second)continue;
ans=max(ans,v1[i].first+v2[j].first+v3[k].first);
}
}
}
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}

E

这里我就写E1和E2的通解了,因为E1和E2只有数据范围不同。

这道题还是很有意思的,我们先思考一下什么样的颜色的弹珠会被先选

在自己的回合,我们想要消去弹珠的差距。

我们就是在想保有自己最多的情况下还要消去对面的最多,也就是自己的x和对面的y最好都很大,所以就按x+y排序就好

然后模拟按分别取的得分获得结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<bits/stdc++.h>
using namespace std;
using i64=long long;
const int N=2e5+10;

void solve(){
int n;cin>>n;
vector<int>a(n);
vector<int>b(n);
vector<int>c(n);
for(int i=0;i<n;i++)cin>>a[i];
for(int i=0;i<n;i++)cin>>b[i];
iota(c.begin(),c.end(),0);
sort(c.begin(),c.end(),[&](int x,int y){
return a[x]+b[x]>a[y]+b[y];
}
);
i64 ans=0;
bool turn=true;
for(auto &i:c){
if(turn){
ans+=a[i]-1;
}else{
ans-=b[i]-1;
}
turn^=1;
}
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _;cin>>_;
while(_--)solve();
return 0;
}