真心感觉是字符串专场。。。。
A
题意:
给你一个字符串,问这个字符串是不是按照m(M), e(E), o(O), w(W)的顺序排列,连续也行,不区分大小写
思路:
就是模拟,找到不相同的地方再把每个区间扫一下看是不是对应的字母就行了,代码写的有点长把大小写字母处理成相同的就是了
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
int n, m, k, _;
int arr[N];
void solve()
{
string s;
cin >> n >> s;
int l1 = 1e9, l2 = 1e9, l3 = 1e9;
set<char> st;
for(int i = 0; i < s.length(); i ++)
{
if(s[i] == 'M') st.insert('m');
else if(s[i] == 'E') st.insert('e');
else if(s[i] == 'O') st.insert('o');
else if(s[i] == 'W') st.insert('w');
else st.insert(s[i]);
}
if(st.size() != 4)
{
cout << "NO" << endl;
return;
}
for(int i = 0; i < s.length(); i ++)
{
if(s[i] != 'm' && s[i] != 'M') l1 = min(l1, i);
}
for(int i = 0; i < l1; i ++)
{
if(s[i] != 'm' && s[i] != 'M')
{
cout << "NO" << endl;
return;
}
}
for(int i = l1; i < s.length(); i ++)
{
if(s[i] != 'e' && s[i] != 'E') l2 = min(l2, i);
}
for(int i = l1; i < l2; i ++)
{
if(s[i] != 'e' && s[i] != 'E')
{
cout << "NO" << endl;
return;
}
}
for(int i = l2; i < s.length(); i ++)
{
if(s[i] != 'o' && s[i] != 'O') l3 = min(l3, i);
}
for(int i = l2; i < l3; i ++)
{
if(s[i] != 'o' && s[i] != 'O')
{
cout << "NO" << endl;
return;
}
}
for(int i = l3; i < s.length(); i ++)
{
if(s[i] != 'w' && s[i] != 'W')
{
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
}
signed main()
{
IOS;
cin >> _;
while(_--)
solve();
return 0;
}
B
题意:
给你长度为n的一个字符串,还有k次操作次数,每一次操作你可以将大小写字母互相转换,最多K次操作下问有多少对大小写相同的字母例如(A, a)。
思路:
就是简单的计算,先把每种字母的个数统计一下,答案肯定是这种字母的最小值,再加上他们能操作的次数和k的最小值,他们能操作的次数(一定是个数差的绝对值除2)。
```cpp
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
int n, m, k, _;
int arr[N];
void solve()
{
string s;
cin >> n >> k >> s;
map<char, int> mp;
for(int i = 0; i < n; i++) mp[s[i]]++;
int ans = 0;
for(int i = 97; i <= 122; i ++)
{
int a = mp[(char)i];
int b = mp[(char)(i-32)];
ans += min(a, b);
if(k != 0)
{
int g = abs(a-b) / 2;
ans += min(g, k);
k -= min(g, k);
}
}
cout << ans << endl;
}
signed main()
{
IOS;
cin >> _;
while(_--)
solve();
return 0;
}
C1&C2
题意:
你现在有一堆卡牌,卡牌的类型有两种,英雄卡和伤害卡。每个英雄初始伤害为0,我们从牌顶开始取牌,如果这个牌为伤害牌我们就将他放到伤害牌这个牌堆,你可以选择将伤害牌丢弃或者放到最上面。如果这张牌是英雄卡,那么你要将伤害牌堆种最上面的那张伤害牌的伤害加给英雄牌,然后英雄就将被添加到军队中,问军队能达到的最大伤害是多少。
思路:
枚举每一张牌,如果这张牌为伤害牌我们就将他加入到优先队列(从大到小),如果为英雄牌我们就取出牌顶。模拟一下就是了。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
using namespace std;
const int N = 2e5 + 10;
int n, m, k, _;
int arr[N];
void solve()
{
priority_queue<int, vector<int>, less<>> q;
cin >> n;
for(int i = 1; i <= n; i ++) cin >> arr[i];
int ans = 0;
for(int i = 1; i <= n; i ++)
{
if(arr[i] == 0)
{
if(q.size() == 0) continue;
ans += q.top();
q.pop();
}
else q.push(arr[i]);
}
cout << ans << endl;
}
signed main()
{
IOS;
cin >> _;
while(_--)
solve();
return 0;
}
D
题意:
给你一个字符串你可以删除任意连续两个字母,然后将剩下的字符串拼接起来,问这样操作过后有多少种字符串。
思路:
首先想了一下应该是贪心,然后师兄说用字符hash更好理解,然后就去学了一下字符hash,这道题居然卡131了,难点就是查询两个子串拼接的hash值,在网上学了一下链接: 拼接,看懂了过后就是一道妥妥的模板题了。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define int long long
#define endl "\n"
using namespace std;
typedef unsigned long long ull;
const int N = 2e5 + 10, P = 13331;
int n, m, k, _;
int arr[N];
char str[N];
ull h[N], p[N];
ull get(int l, int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
ull get_s1_s2(int l1, int r1, int l2, int r2)
{
return get(l1, r1)*p[r2-l2+1] + get(l2, r2);
}
void solve()
{
cin >> n >> (str+1);
p[0] = 1;
for(int i = 1; i <= n; i ++)
{
p[i] = p[i-1]*P;
h[i] = h[i-1]*P+str[i];
}
set<ull> st;
st.insert(get(3, n));
st.insert(get(1, n-2));
for(int i = 1; i <= n-3; i ++)
{
st.insert(get_s1_s2(1, i, i+3, n));
}
cout << st.size() << endl;
}
signed main()
{
IOS;
cin >> _;
while(_--)
solve();
return 0;
}
E1 & E2
题意:
给你两个长度为n的字符串s,t,还有一个k,如果 ∣ i − j ∣ = k ∣ ∣ ∣ i − j ∣ = k + 1 , i ≤ n , j ≤ n |i-j| = k \ \ || \ \ |i - j| = k+1,i \le n, j\le n ∣i−j∣=k ∣∣ ∣i−j∣=k+1,i≤n,j≤n,你就可以交换s[i], s[j],操作次数不限。问能够将s变成t吗?
思路:
如果对于当前i, i ≥ k ∣ ∣ i + k ≤ n i \ge k \ \ || \ i+k \le n i≥k ∣∣ i+k≤n,那么i可以到1~n-k任意一个位置上去,所以我们只需要判断当他们无法移动时 s [ i ] = t [ i ] s[i] = t[i] s[i]=t[i]是否成立,如果不成立就直接输出NO,当然我们首先还是要判断一下两个字符串中字母种类和对应的数量是否相同。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define endl "\n"
//#define int long long
using namespace std;
const int N = 2e5 + 10;
int n, m, k, _;
char s[N], t[N];
map<char, int> ck(char *s)
{
map<char, int> mp;
for(int i = 1; i <= n; i ++)
{
mp[s[i]]++;
}
return mp;
}
void solve()
{
cin >> n >> k >> s+1 >> t+1;
if(s == t) cout << "YES" << endl;
else
{
if(ck(s) != ck(t))
{
cout << "NO" << endl;
return;
}
for(int i = 1; i <= n; i ++)
{
if(i <= k && i+k > n && s[i] != t[i])
{
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
}
}
signed main()
{
IOS;
cin >> _;
while(_--)
solve();
return 0;
}
F
题意:
给你n个字符串(由小写字母构成),你要选择任意两个字符串拼接起来,如果满足一下三个条件那么数量+1:
1.这两个字符串拼接起来的长度为奇数;
2.拼接起来的字符串的字母种类要刚好是25个;
3.拼接起来的字符串每个字母出现的次数是奇数。
问有多少对不同的<i, j>。
思路:
这个题师兄提了一下是hash异或的,没有学过只有去看一下题解了。
链接: 讲解,这篇题解讲的很好,感兴趣的同学可以去看一下。
最开始我理解那个预处理其实理解了很久,但是一定要结合二进制和逻辑运算,包括二进制枚举去理解。昨晚这道题感觉异或运算是真的好,完美可以去判断奇偶。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define endl "\n"
//#define int long long
#define pb push_back;
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
int n, m, k, _;
string s;
int a[N], b[N], cnt[1 << 26];
void judge(int x)
{
vector<int> p;
while(x)
{
p.push_back(x % 2);
x /= 2;
}
for(int i = p.size() - 1; i >= 0; i --) cout << p[i];
cout << endl;
}
signed main()
{
IOS;
cin >> n;
for(int i = 1; i <= n; i ++)
{
cin >> s;
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 ++)
{
int op = (1 << 26) - 1 - (1 << i);
for(int j = 1; j <= n; j ++)
{
if(!(a[j] >> i & 1))
{
cnt[b[j]]++;
ans += cnt[b[j]^op];
}
}
for(int j = 1; j <= n; j ++ ) if(!(a[j] >> i & 1)) cnt[b[j]] -- ; // 清空 cnt 数组
}
cout << ans << endl;
return 0;
}