日常刷题2025-1-23

日常刷题2025-1-23

rating:1400

https://codeforces.com/problemset/problem/1955/D

思路(定长滑动窗口)

定长滑动窗口,r 只管加, l 只管减即可。

代码

#include <bits/stdc++.h>

typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;

void solve(){
	int n, m, k;
	std::cin >> n >> m >> k;

	std::map<int, int> dic;
	std::vector<int> a(n), b(m);
	for (int i = 0; i < n; i++){
		std::cin >> a[i];
	}	
	for (int i = 0; i < m; i++){
		std::cin >> b[i];
		dic[b[i]] += 1;
	}

	std::map<int, int> mp;
	int l = 0, r = 0, cnt = 0, ans = 0;
	while (r < n){
		if (dic[a[r]] != 0) {
			mp[a[r]] += 1;
			if (mp[a[r]] <= dic[a[r]]) cnt++;
		}
		if (r - l + 1 < m) {
			r++;
			continue;
		}
		ans += cnt >= k;
		if (dic[a[l]] != 0){
			mp[a[l]] -= 1;
			if (mp[a[l]] < dic[a[l]]) cnt--;
		}
		l++;
		r++;
	}

	std::cout << ans << '\n';
}

signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
	int t = 1, i;
	std::cin >> t;
	for (i = 0; i < t; i++){
		solve();
	}
	return 0;
}

C. Ticket Hoarding

rating:1400

https://codeforces.com/problemset/problem/1951/C

思路(贪心)

看着像DP,但是一看 k 的取值范围,DP放弃,只能想一想贪心。如果有一个购买序列b,b任意排序不会影响最终的增量add,因为增加的值是确定的。所以我们可以排序,每次贪心的买价格最少的就行。

代码

#include <bits/stdc++.h>

typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;

void solve(){
	int n, m, k;
	std::cin >> n >> m >> k;

	std::vector<int> a(n+1);
	for (int i = 1; i <= n; i++){
		std::cin >> a[i];
	}	
	std::sort(a.begin() + 1, a.end());

	i64 ans = 0, add = 0;
	for (int i = 1; i <= n; i++){
		ans += std::min(m, k) * (a[i] + add);
		add += std::min(m, k);
		k -= std::min(m, k);
	}

	std::cout << ans << '\n';
}

signed main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
	int t = 1, i;
	std::cin >> t;
	for (i = 0; i < t; i++){
		solve();
	}
	return 0;
}

E. Nearly Shortest Repeating Substring

rating:1500

https://codeforces.com/problemset/problem/1950/E

思路(枚举因子+小巧思)

我们先思考一下知道循环长度时答案可能是什么,假设循环长度为 x,答案序列为 k ,则答案一定是 s 字符串开头 x 个或者 s 字符串最后 x 个之一。为什么?

如果开头 x 个不可行,那么说明开头 x 个字符中至少有一个字符与 k 不同,如果最后 x 个也不行,也说明同样的结果,那么如果选开头和选结尾都不行的话,选其他任何的x个字符也一定不行,因为开头和结尾已经各有一个和答案序列不同了。所以 x 这个长度的循环行不行取决为开头和结尾 x 个字符。

那么如何得到 x 呢?

很显然 x 一定只能是 n 的因子,所以我们只需要 log n 的复杂度枚举每一个可行的 x 然后计算是否可行即可。\(O(n * log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 5;

vector<int> e[maxn];

int n;
string s, t;

bool check(int x) {
    int cnts = 0, cntt = 0;
    for (int i = x; i < n; i++) {
        if (s[i % x] != s[i]) cnts++;
        if (t[i % x] != t[i]) cntt++;
    }
    if (cnts <= 1 || cntt <= 1) return true;
    return false;
}

void solve() {
    cin >> n >> s;
    t = s;
    reverse(t.begin(), t.end());
    vector<int> v;
    for (int i = 1; i * i <= n; i++) {
        if (n % i != 0) continue ;
        v.push_back(n / i);
        v.push_back(i);
    }
    sort(v.begin(), v.end());

    for (int i = 0; i < v.size(); i++) {
        if (check(v[i])) {
            cout << v[i] << endl;
            return ;
        }
    }

}

int main() {
    int T = 1;
    cin >> T;
    while (T--) solve();
}

posted @ 2025-01-23 09:28  califeee  阅读(26)  评论(0)    收藏  举报