牛客小白月赛101
A - tb的区间问题
枚举区间,然后用前缀和求解
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, k;
cin >> n >> k;
vi a(n + 1);
for(int i = 1; i <= n; i ++)
cin >> a[i], a[i] += a[i-1];
int res = 0;
for(int l = 1, r = n - k; r <= n; l ++, r ++)
res = max(res, a[r] - a[l - 1]);
cout << res;
return 0;
}
B -tb的字符串问题
栈模拟一下
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
string s;
cin >> s;
string t;
for(auto c : s){
if(not t.empty() and ((t.back() == 'f' and c == 'c') or (t.back() == 't' and c == 'b')))
t.pop_back();
else t += c;
}
cout << t.size();
return 0;
}
C - tb的路径问题
找规律,发现对于对角线上的每个数字两步之内必有\(2\),但是对于奇数来说,两步之内的\(2\)在\(n\times n\) 的外面,因此只能走到前一个偶数上。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using vi = vector<int>;
using pii = pair<int,int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
cout << min(2 * n - 2 , 4 + 2 * (n % 2));
return 0;
}
D - tb的平方问题
发现询问的范围并不大,所以我们可以离线计算。
可以枚举出所有的完全平方数,然后利用枚举+二分找到所有的区间,并用差分实现区间修改。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int,int>;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n , q;
cin >> n >> q;
vi a(n + 1);
for(int i = 1; i <= n; i ++)
cin >> a[i], a[i] += a[i - 1];
int sum = a[n];
vi p2;
for(int i = 1; i * i <= sum; i ++)
p2.push_back(i * i);
vi res(n + 2);
for(const int &v : p2){
for(int l = 1, r, x ; l <= n; l ++){
x = a[l - 1] + v;
if(x > sum) break;
r = ranges::lower_bound(a, x) - a.begin();
if(a[r] - a[l - 1] == v)
res[l] ++, res[r + 1] --;
}
}
for(int i = 1; i <= n ; i ++)
res[i] += res[i - 1];
for(int x ; q ; q -- ){
cin >> x;
cout << res[x] << "\n";
}
return 0;
}
E - tb的数数问题
用一个类似埃筛的做法,求出每个数的约数个数,然后再已有的约数,然后比较一下就好了。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int,int>;
const int N = 1e6;
bitset<N + 1> vis;
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
for(int i = 1, x; i <= n; i ++)
cin >> x, vis[x] = true;
vi a(N + 1);
for(int i = 1; i <= N; i ++)
for(int j = i; j <= N; j += i) a[j] ++;
vi b(N + 1);
for(int i = 1; i <= N; i ++ ){
if(vis[i] == false) continue;
for(int j = i; j <= N; j += i) b[j] ++;
}
int res = 0;
for(int i = 1; i <= N; i++)
res += a[i] == b[i];
cout << res;
return 0;
}
F - tb的排列问题
用\(pos[x]\)统计\(a_i\)中非\(-1\)的数出现的位置。用\(pre[x]\)维护出\(a\)前缀中\(-1\)个数。
我们从前往后考虑每一个\(b_i\),对于这个数来说,能够和他交换的范围是\([i,i+w]\)。
如果\(b_i\)存在于\(a\)中,且在这个范围\([1,i+w]\)内就可以交换过来,答案乘\(1\),否则答案乘\(0\)。考虑为什么\([1,i-1]\)也可以,因为我们从前往后枚举,所以前缀是一定匹配的,因为如果出现在前面,一定会在之前的某次交换到后面。
如果\(b_i\)不存在于\(a\)中,则需要消耗\([1,i+w]\)内一个\(-1\),同时考虑到之前可能已经消耗了一些\(-1\)所以我们要计算出还剩下了多少\(-1\),答案乘以剩下\(-1\)的个数即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int,int>;
const int N = 1e6;
bitset<N + 1> vis;
const int mod = 998244353;
struct mint {
int x;
mint(int x = 0) : x(x) {}
mint &operator=(int o) { return x = o, *this; }
mint &operator+=(mint o) { return (x += o.x) >= mod && (x -= mod), *this; }
mint &operator-=(mint o) { return (x -= o.x) < 0 && (x += mod), *this; }
mint &operator*=(mint o) { return x = (i64) x * o.x % mod, *this; }
mint &operator^=(int b) {
mint w = *this;
mint ret(1);
for (; b; b >>= 1, w *= w) if (b & 1) ret *= w;
return x = ret.x, *this;
}
mint &operator/=(mint o) { return *this *= (o ^= (mod - 2)); }
friend mint operator+(mint a, mint b) { return a += b; }
friend mint operator-(mint a, mint b) { return a -= b; }
friend mint operator*(mint a, mint b) { return a *= b; }
friend mint operator/(mint a, mint b) { return a /= b; }
friend mint operator^(mint a, int b) { return a ^= b; }
int val() {
x = (x % mod + mod) % mod;
return x;
}
};
void solve() {
int n, w;
cin >> n >> w;
vi a(n + 1);
for(int i = 1; i <= n; i ++)
cin >> a[i];
vi b(n + 1);
for(int i = 1; i <= n; i ++)
cin >> b[i];
vi pos(n + 1, -1);
for(int i = 1; i <= n; i ++)
if(a[i] != - 1) pos[a[i]] = i;
vi pre(n + 1);
for(int i = 1; i <= n; i ++)
pre[i] = pre[i - 1] + (a[i] == -1);
mint res(1);
for(int i = 1, used = 0; i <= n ;i ++){
if(pos[b[i]] != -1) {
res *= pos[b[i]] <= min(i + w, n);
} else {
res *= pre[min(i + w, n)] - used;
used ++;
}
}
cout << res.val() << "\n";
return;
}
i32 main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --)
solve();
return 0;
}