牛客练习赛51
A - abc
题意:
给出字符串\(s\),要求统计\(s\)中子序列为\("abc"\)的个数。
思路:
分别统计一下前缀\(a\)和后缀\(c\)的个数即可。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
const int N = 1e5 + 5;
ll qp(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
char s[N];
int prea[N], sufc[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> s + 1;
int n = strlen(s + 1);
for(int i = 1; i <= n; i++) {
prea[i] = prea[i - 1] + (s[i] == 'a');
}
for(int i = n; i >= 1; i--) {
sufc[i] = sufc[i + 1] + (s[i] == 'c');
}
ll ans = 0;
for(int i = 1; i <= n; i++) {
if(s[i] == 'b') ans += 1ll * prea[i] * sufc[i];
}
cout << ans;
return 0;
}
B - 子串查询
题意:
给出一个字符串\(s\),之后有多个询问,每个询问会有一个串\(t\),回答\(t\)是否为\(s\)的子序列。
思路:
预处理下一位,模拟一下即可。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
const int N = 1e5 + 5;
ll qp(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
int n, q;
char s[N];
char t[55];
int nxt[N][26], Next[26];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> q;
cin >> s + 1;
for(int i = n; i >= 0; i--) {
for(int j = 0; j < 26; j++) {
nxt[i][j] = Next[j];
}
Next[s[i] - 'a'] = i;
}
for(int i = 1; i <= q; i++) {
cin >> t + 1;
int now = 0, len = strlen(t + 1), f = 1;
for(int j = 1; j <= len; j++) {
now = nxt[now][t[j] - 'a'];
if(now == 0) {
f = 0; break;
}
}
if(now == 0) cout << "NO" << '\n';
else cout << "YES" << '\n';
}
return 0;
}
C - 勾股定理
数学题,百度一下...
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
const int N = 1e5 + 5;
ll qp(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
ll n;
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n;
if(n < 3) {
cout << -1; return 0;
}
if(n & 1) {
ll b = (n * n - 1) / 2, c = (n * n + 1) / 2;
cout << b << ' ' << c << '\n';
} else {
ll tmp = n * n / 2;
if(tmp % 2 != 0) {
cout << -1;
} else {
ll b = (n * n / 2 - 2) / 2, c = (n * n / 2 + 2) / 2;
cout << b << ' ' << c;
}
}
return 0;
}
D - 羊吃草
题意:
现在有一个长度为\(400\)的数轴,并且存在\(n\)头羊,每头羊会吃范围在\([a_i,b_i]\)上面的草,每头羊只能吃一个位置上面的草并且一个位置只能被一只羊吃。
现在有多个询问,对于每个询问会有一个区间\([l,r]\),询问区间\([l,r]\)上最多有多少只羊在这上面吃草。
思路:
显然可以直接二分图最大匹配来搞。
但有一种很好写的方法:
- 对于每次的询问,我们每个位置逐一考虑。
- 当我们考虑到位置\(i\)时,我们会选择一头羊来进行匹配,这时贪心选择即可,前提是羊吃草的区间包含\(i\)。
- 具体来说,就是每个羊尽量在最后时刻才吃草,那么我们在前面的时刻都可以选择。
- \(i\)位置考虑完了过后,我们要把最晚位置为\(i\)且还没匹配的羊删去,这是显然的。
这可以用\(multiset\)来维护,\(erase\)某个值时能将那个值全部删除。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 405;
multiset <int> s;
int n, q;
int a[N], b[N];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> q;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) cin >> b[i];
while(q--) {
s.clear();
int l, r; cin >> l >> r;
int ans = 0;
for(int i = 1; i <= n; i++) {
if(a[i] < l && b[i] >= l) s.insert(b[i]);
}
for(int i = l; i <= r; i++) {
for(int j = 1; j <= n; j++) if(i == a[j]) s.insert(b[j]);
if(s.size()) ++ans, s.erase(s.begin());
s.erase(i);
}
cout << ans << '\n';
}
return 0;
}
E - 数列
题意:
现在有长度为\(n\)的空位,现在我们要往中间填入一些数。
若存在对于\(i>1,a[i]=a[i-1]+1\),那么答案会加一。
先问怎么分配,能使答案最大并且总和不超过\(m\)。
思路:
- 注意到肯定是\(1,2,\cdots,1,\cdots\)这样来是最优的。
- 我们将连续递增的几个数统称为“块”,显然,假设最终有\(x\)块,那么答案就为\(n-x\);
- 并且可以发现:块越多,总和越小;否则总和越大,也就是说块的数量是具有单调性的,那么我们就可以二分块的个数。
- 怎么分配?
- 注意到若存在:\(1,2,\cdots,x,1,2,\cdots,y\)并满足\(y>x+1\)这种,那么我们将\(y\)放到\(x\)后面(变为\(x+1\)了)是肯定更优的。
- 所以就平均分配就行了~
简洁来说,就是二分+均分即可,这些性质也比较显然。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, m;
bool chk(int x) {
int p = n / x;
int q = n % x;
ll now = 1ll * q * (p + 1) * (p + 2) / 2;
now += 1ll * (x - q) * (p + 1) * p / 2;
return now <= m;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m;
int l = 1, r = n + 1, mid;
while(l < r) {
mid = (l + r) >> 1;
if(chk(mid)) r = mid;
else l = mid + 1;
}
int p = n / r, q = n % r;
for(int i = 1; i <= q; i++) {
for(int j = 1; j <= p + 1; j++) {
cout << j << ' ';
}
}
for(int i = 1; i <= r - q; i++) {
for(int j = 1; j <= p; j++) {
cout << j << ' ';
}
}
return 0;
}
重要的是自信,一旦有了自信,人就会赢得一切。