紫书 例题8-15 UVa 12174 (滑动窗口)

这道题就是给你一n长序列, 然后把这个序列按顺序分成很多段, 每段长s(最前面可以小于s, 只有第一段的后半段, 最后面也同样, 只有最后一段的前半段), 然后要求是每一段里面没有重复的数, 问你有几种分法

实际上看到连续s个数, 就可以想到滑动窗口, 可以提前初始化所给序列的每一段里面有没有重复的数, 然后再枚举第一段的终点, 然后一段一段去判断是否全部都没有重复的数字, 如果所有段都是的话, 那么就符合题目要求, ans++

有两个地方要注意

(1)初始化的问题。这个思路有点像扫描法, 判断每一段的时候, 不用从新开始, 而是从相邻左边的那一段, 把最前面的数字减去和新加的数字加进来就可以了, 利用好前面得出的结果。我一开始每一段都重新算, 然后就超时了


(2)不是完整的段的问题。如果是最前面的那一段, 那么只算序列里面的那一段, 然后最后面的那一段也是只算序列里面的那一段,所以要特别注意, 结尾可以到n + s - 1, 同时保存这个数组空间就要翻倍了。


#include<cstdio>
#include<cstring>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std;

const int MAXN = 112345;
int a[MAXN], vis[MAXN], n, s;
bool k[MAXN<<1];  //翻倍 

void init()
{
	int cnt = 0;  //重复数字的个数 
	memset(k, false, sizeof(k));
	memset(vis, 0, sizeof(vis));
	
	vis[a[0]]++;
	REP(i, 0, n + s)  //一定是n+s 
	{
		k[i] = (cnt == 0);
		if(i + 1 < n && ++vis[a[i+1]] == 2) cnt++;  //注意这里一定是==2, 因为这代表从1到2, 而不是 > 1 
		if(i - s + 1>= 0 && --vis[a[i-s+1]] == 1) cnt--; //同上, 代表从2到1。 
	}
}


bool judge(int end)
{
	while(1)
	{
		if(!k[end]) return false;
		if(end >= n) return true; //如果到最后的那一段都符合的话, 那就这种情况符合要求 
		end += s;
	}
}

int main()
{
	int T;
	scanf("%d", &T);
	
	while(T--)
	{
		scanf("%d%d", &s, &n);
		REP(i, 0, n) scanf("%d", &a[i]);
		init();
		
		int ans = 0;
		REP(i, 0, s) ans += judge(i);
		printf("%d\n", ans);
	}
	
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值