牛客小白月赛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;
}
posted @ 2024-09-23 14:34  PHarr  阅读(12)  评论(0编辑  收藏  举报