A. Everything Everywhere All But One
题意:给出n个数,每一次操作可以选择n-1个数,将它们代替为它们的算术平均值(分数也可以),问任意次操作后是否可以使得全部数相等。
思路:如果选择的这n-1个数的算数平均值为分数,那么不管操作多少次都不可能使得全部数相等,因为另外一个数为整数。对全部数求和,然后遍历1-n,每次选择除了第i个数的另外n-1个数判断是否整除(n-1)且商等于a[i]即可。
AC code:
#include <bits/stdc++.h>
using namespace std;
int n,a[60];
void solve(){
cin>>n;
long long sum=0;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
// cout<<sum<<endl;
for(int i=1;i<=n;i++){
int t=sum-a[i];
// cout<<t<<' ';
if((t%(n-1))==0){
int tt=t/(n-1);
if(tt==a[i]){
cout<<"YES"<<endl;
return ;
}
}
}
cout<<"NO"<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
B. Odd Subarrays
题意:给出n个数,问怎样切分这n个数,使得尽可能多的子数组中逆序对数为奇数。
思路:要使子数组尽可能的多且子数组中逆序对数为奇数,则就选相邻的逆序对为一个子数组即可,遍历一遍判断一下即可。注意:是切分,不能重复。
AC code:
#include <bits/stdc++.h>
using namespace std;
int n,a[100010];
int main(){
int t;
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int cnt=0;
for(int i=1;i<n;i++){
if(a[i]>a[i+1]){
cnt++;
i++;
}
}
cout<<cnt<<endl;
}
return 0;
}
C. Circular Local MiniMax
题意:n个数形成一个环,对这n个数进行排列,问是否存在一种情况使得每个数要么同时比它相邻的数大,要么同时比它相邻的数小。
思路:可以按照一小一大进行排列,那么n为奇数时一定不能满足题意,n为偶数时,对n个数进行排序,然后一小一大放置,最后遍历一遍检验是否满足同时大或者同时小。
AC code:
#include <bits/stdc++.h>
using namespace std;
int n,a[100010],b[100010];
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
if(n&1){
cout<<"NO"<<endl;
return ;
}
sort(a+1,a+n+1);
for(int i=0;i<=n+1;i++) b[i]=0;
b[0]=a[n],b[n+1]=a[1];
int j=1;
for(int i=1;i<=n;i+=2){
b[i]=a[j];
j++;
}
j=n/2+1;
for(int i=2;i<=n;i+=2){
b[i]=a[j];
j++;
}
// cout<<endl;
// for(int i=1;i<=n;i++) cout<<b[i]<<' ';
// cout<<endl;
for(int i=1;i<=n;i++){
if(b[i]==b[i-1] || b[i]==b[i+1]){
cout<<"NO"<<endl;
return ;
}
}
cout<<"YES"<<endl;
for(int i=1;i<=n;i++) cout<<b[i]<<' ';
cout<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
D. Linguistics
题意:告诉你‘A’,‘B’,‘AB’,‘BA’的数量,并且给出一个字符串仅含有‘A’和‘B’,判断用给出的元素是否能组成该字符串。
思路:学习的大佬的思路:Codeforces Round #794 (Div. 2 + Div. 1) A-D - 知乎 (zhihu.com),大概就是求出组成该字符串所需的最小的‘A’,‘B’,‘AB’,‘BA’数量,然后判断是否满足给出的数量。首先判断是否‘A’的数量等不等于a+c+d,不相等一定不满足题意。
然后去找类似连续的不相等子串,例如:ABABA,BABA....当子串长度为偶数时,且单‘A’和单‘B’没有剩余时,那么对‘AB’或者‘BA’的贡献数量就是len/2,如果有单‘A’和单‘B’剩余,则可以将头尾与该子串断开,若原来是ABABAB,则断开后就为BABA了,那么断开后的子串对‘AB’就不再有贡献了。
BA开头的偶数子串同理。当子串长度为奇数时,可以切除头或者尾从而得到偶数子串,并且对单‘A’或者单‘B’的贡献为1。最后从长的偶数子串开始断开,这样能保证最后求出的是最少数量。
AC code:
#include <bits/stdc++.h>
using namespace std;
int a,b,c,d,cnt[200010];
char s[200010];
void solve(){
cin>>a>>b>>c>>d;
cin>>s+1;
int n=strlen(s+1);
int num=count(s+1,s+n+1,'A');
if(num!=a+c+d){
cout<<"NO"<<endl;
return ;
}
vector<int> ab,ba;
int cntab=0,cntba=0;
for(int i=1;i<=n;i++){
int j=i;
while(j+1<=n && s[j]!=s[j+1]) j++;
if(j-i+1&1){
if(s[i]=='A'){
a--;
}else{
b--;
}
}else{
if(s[i]=='A'){
cntab+=((j-i+1)>>1);
ab.push_back(((j-i+1)>>1));
}else{
cntba+=((j-i+1)>>1);
ba.push_back((j-i+1)>>1);
}
}
i=j;
}
if(a<0 || b<0){
cout<<"NO"<<endl;
return ;
}
{
int t=min(a,b);
sort(ab.begin(),ab.end());
while(!ab.empty() && t){
t--;
cntab-=ab.back();
ab.pop_back();
}
if(cntab>c){
cout<<"NO"<<endl;
return ;
}
}
{
int t=min(a,b);
sort(ba.begin(),ba.end());
while(!ba.empty() && t){
t--;
cntba-=ba.back();
ba.pop_back();
}
if(cntba>d){
cout<<"NO"<<endl;
return ;
}
}
cout<<"YES"<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}