A. Is It a Cat?
分析
模拟题,关键就是看代码怎么写好写
可以先把所有的大写字母变成小写,这样判断时方便一点
string t='m';
然后从第二个字符往后遍历,每次遇到与前一个字符不同的字符,将该字符加入到字符串 t 中,最后看t是否等于meow
C++代码
#include<iostream>
using namespace std;
const int N=200010;
void solve(){
int n;
string s;
cin>>n>>s;
for(int i=0;i<n;i++)
if(s[i]>='A'&&s[i]<='Z')
s[i]=s[i]+32;//全变成小写
string t;
t+=s[0];
for(int i=1;i<s.size();i++)
if(s[i]!=s[i-1])
t+=s[i];
if(t=="meow")puts("Yes");
else puts("No");
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
B. Count the Number of Pairs
分析
找到每个字母的大小写的个数,二者取min就是不改变任何字母对答案的贡献,所有字母最初贡献和用sum记录
cnt记录匹配完后剩下的字母最多对答案的贡献
每个字母匹配完后只会剩下纯大写或纯小写字母,这样对答案的贡献就是字母数量的一半
依次处理每个字母即可
然后判断k和cnt的大小,答案为sum+min(k,cnt)
C++代码
#include<iostream>
using namespace std;
void solve(){
int n,k;
cin>>n>>k;
string s;
cin>>s;
int a[26]={0},b[26]={0};//分别存储大小写字母的个数
for(int i=0;i<s.size();i++){
if(s[i]>='a'&&s[i]<='z')a[s[i]-'a']++;
else if(s[i]>='A'&&s[i]<='Z')b[s[i]-'A']++;
}
int sum=0,cnt=0;
for(int i=0;i<26;i++){
sum+=min(a[i],b[i]);//不变字母就可以找到的大小写字母对数
cnt+=abs(a[i]-b[i])/2;//改变第i个字母最多对答案的贡献
}
//一共只能操作k次,就看cnt和k哪个更小
sum+=min(cnt,k);
cout<<sum<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
C1&C2. Powering the Hero
分析
使用大根堆,从前往后遍历每个数,sum记录答案
遇到0,sum加上堆顶元素,然后堆顶元素出队
遇到非0就将该元素入堆
C++代码
#include<iostream>
#include<queue>
using namespace std;
typedef long long LL;
const int N=5010;
int a[N];
void solve(){
LL n,sum=0;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
priority_queue<int> q;
for(int i=1;i<=n;i++){
if(a[i]==0&&q.size()){
sum+=q.top();
q.pop();
}else{
q.push(a[i]);
}
}
cout<<sum<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
D. Remove Two Letters
分析
因为每次只能删两个相邻元素,所以对于每个元素,会出现在两个删除的序列中
a[i]所在的删除序列就是a[i-1]和a[i],a[i]和a[i+1]这两个
可以发现,如果a[i-1]==a[i+1],则删除这两个序列后形成的新字符串是相同的,所以我们只需要记录一次就好
每次删两个字符,故删除的情况有n-1种,可以形成n-1个新的字符串,答案ans最初为n-1,但是每次遇到s[i-1]==s[i+1]时,我们就要将ans--
C++代码
#include<iostream>
using namespace std;
void solve(){
int n,ans;
string s;
cin>>n>>s;
ans=n-1;
for(int i=1;i<s.size();i++){
if(s[i-1]==s[i+1])ans--;
}
cout<<ans<<'\n';
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
E1&E2. Unforgivable Curse
分析
i可以和i+k,i+k+1交换
i+1可以和i+k+1,i+k+2换
所以i可以和i+1换,一次类推,i,i+1,i+2,... 都是可以互换的,如果所有s[i]和t[i]不同的字符都可以互换,则一定可以将s变成t
所以我们要找到存在s[i]!=t[i]的字符不可以互换的情况
不难发现,只要 i 前面有字符可以到他或者 i 可以到他后面的字符,则i一定可以与其他的字符连通,所以不连通的情况就是i<k&&i+k>=n(字符串编号从0开始)
在找之前需要判断s和t中所含的字母是否相同,如果不同则直接输出NO;否则就进行如上判断
C++代码
#include<iostream>
using namespace std;
void solve(){
int n,k;
cin>>n>>k;
string s,t;
cin>>s>>t;
int a[26]={0},b[26]={0};
for(int i=0;i<n;i++)a[s[i]-'a']++,b[t[i]-'a']++;
for(int i=0;i<26;i++)
if(a[i]!=b[i]){
cout<<"NO"<<'\n';
return;
}
for(int i=0;i<n;i++)
if(s[i]!=t[i]&&i<k&&i+k>=n){
cout<<"NO"<<'\n';
return;
}
cout<<"YES"<<'\n';
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}
F. Dasha and Nightmares
分析
S=s[i]+s[j]有三个条件
1、一共有奇数个字母
2、s[i]中一共有25个英文字母
3、每个英文字母出现的次数都是奇数个
会发现25个奇数相加还是奇数,所以只需要考虑条件2和3即可
记录每个字符串的状态,由于只有26个英文字母,二进制状态一定小于2^26,在int范围内,所以只需要开两个数组a和b
a[i]记录第i个字符串每个字符是否出现;
b[i]记录第i个字符串每个字符的个数是否为奇数,如果是二进制对应位就是1,否则是0
一共25个字符,所以枚举那个不存在的字符(假设编号为i),然后枚举所有不存在该字符的字符串,找到该字符串对应的状态b[j],两个字符串合体成为一个字符串时,它们的状态b直接异或就是新的字符串的状态了,因为只有奇+偶=奇,其余全是偶数
C++代码
#include<iostream>
using namespace std;
typedef long long LL;
const int N=200010;
int a[N],b[N],cnt[1<<26];
string s;
int n;
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>s;
//初始化a[i]和b[i]
for(int j=0;j<s.size();j++)
a[i]|=(1<<(s[j]-'a')),b[i]^=(1<<(s[j]-'a'));
}
LL ans=0;
for(int i=0;i<26;i++){//枚举每个字母不在的情况,0~25表示a~z
int t=(1<<26)-1-(1<<i);//一共25个字母,i+'a'不存在的情况
for(int j=1;j<=n;j++){//枚举n个字符串
if(!(a[j]>>i&1)){//第i个字母必须不存在
cnt[b[j]]++;
ans+=cnt[b[j]^t];
}
}
//清空cnt数组
for(int j=1;j<=n;j++)
if(!(a[j]>>i&1))cnt[b[j]]--;
}
cout<<ans<<endl;
}
int main(){
solve();
return 0;
}