日常刷题2025-3-4

日常刷题2025-3-4

P1381 单词背诵

绿色

https://www.luogu.com.cn/problem/P1381

思路

先考虑最多,再考虑尽量短。最多肯定是所以单词都包含的时候。所以本题的意思其实是让我们找最短的区间包含所有要背的单词。

双指针做法。

wa 了很多发,原因是有一个极端条件没有考虑到。那就是当文章中一个要背的单词都没有时答案是0 0。需要最后对ans做一个判断。

代码

#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, cnt = 0;
	std::cin >> n;
	std::map<std::string, int> a;
	for (int i = 0; i < n; i++) {
		std::string s;
		std::cin >> s;
		a[s] = 1;
	}
	std::cin >> m;
	std::vector<std::string> b(m);
	for (int i = 0; i < m; i++) {
		std::cin >> b[i];
		if (a[b[i]] == 1){
			a[b[i]]++;
			cnt++;
		}
	}

	std::map<std::string, int> dic;
	int w = 0; // 至少出现一次的单词的个数

	int ans = 1e9;
	for (int i = 0, j = 0; i < m; i++){
		if (a[b[i]] < 1) continue;
		dic[b[i]]++;
		if (dic[b[i]] == 1){
			w++;
		}
		while (j < m && w == cnt){
			ans = std::min(i - j + 1, ans);
			if (a[b[j]] < 1) {
				j++;
				continue;
			}
			dic[b[j]]--;
			if (dic[b[j]] == 0) w--;
			j++;
		}
	}

	std::cout << cnt << '\n';
	std::cout << (ans == 1e9 ? 0 : 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;
	for (i = 0; i < t; i++){
		solve();
	}
	return 0;
}

P6465 [传智杯 #2 决赛] 课程安排

思路:滑动窗口

长度至少为 l 的滑动窗口

如果某个状态的首尾指针相同,则 j++

如果 a[i] == a[i-1] 则 j 需要直接移动到 i 的位置,因为包含 i 和 i - 1 这两个位置的状态都是不合法的。

但是遇到1个问题

  • 如何判断一个答案之前出现过,每个答案的长度是不固定的,无法使用集合加定长的array来存标定答案。

事实是这个问题是我没有好好读题导致的,题目中说了判断两个答案不是同一个答案的标准是在原序列中的位置不一样,跟内容没什么关系。

正解:双指针

固定右,枚举左,统计答案

https://www.luogu.com.cn/article/y7t2yi9c

代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=5e5+10;
int T,n,l,r,a[N],cnt[N];
void solve() {
	scanf("%d%d",&n,&l);ll res1=0,res2=0;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),cnt[i]=0;
	r=0;
	for(int i=1;i<=n;i++) {
	    if(i>r) r++,cnt[a[r]]++;
		while(r<n&&a[r]!=a[r+1]) ++r,++cnt[a[r]];
		--cnt[a[i]];
		res1+=r-i+1-cnt[a[i]];
	} 
	r=0;
	for(int i=1;i<=n;i++) {
		if(i>r) ++r,cnt[a[r]]++;
		while(r<n&&a[r]!=a[r+1]&&r+1-i+1<l) ++r,++cnt[a[r]];
		--cnt[a[i]];
		res2+=r-i+1-cnt[a[i]];
	} 
	printf("%lld\n",res1-res2); 
}
int main() {
	scanf("%d",&T);
	while(T--) solve();
	return 0;
}
posted @ 2025-03-04 20:54  califeee  阅读(48)  评论(0)    收藏  举报