UVa11536 Smallest Sub-Array解题报告
题目链接
又是一个优化枚举次数的题目,这次一定要记录下来,学会这种解题思路。
题目分析
题目的意思是,需要在一个数组中,找到包含
[
1
,
K
]
[1,K]
[1,K]中所有整数的最短长度的子数组。
当时我的思路是通过枚举起点,然后通过二分法来找到终点。然后超时了。。。。然后发现是我的枚举对象搞错了,以后解题要首先明确枚举对象是什么。
根据网上的解题报告,可以选满足条件的最短长度作为枚举对象,然后二分查找,由于满足条件的长度
1
≤
l
e
n
≤
N
1\leq len \leq N
1≤len≤N ,每次枚举后通过滑动窗口来判断是否满足条件,时间复杂度为
O
(
N
)
O(N)
O(N),所以总共的时间复杂度为
O
(
N
log
N
)
O(N\log N)
O(NlogN)
算法设计
取枚举区间为左闭右开区间,初始L=1、R=N+1。如果当前枚举的值满足条件说明还可以继续往小了分,否则就应该往大了分。
判断是否满足条件用滑动窗口法,假设当前枚举长度为
l
e
n
len
len,那么我们通过扫描一遍数组,每次只需要判断右边滑进来的元素、和左边滑出去的元素,这样就可以在
O
(
N
)
O(N)
O(N)时间内得到结果。
完整代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 1000000 + 10000;
const int maxk = 1000+200;
int seq[maxn];
int cnt[maxk];
//前缀和
int N, M, K;
//尝试用长度为len的滑动窗口
bool judge(int len)
{
//用来保存在滑动窗口中出现数字的总数
int tot = 0;
//cnt[i]记录出现数字i的次数
memset(cnt, 0, sizeof(cnt));
//滑动窗口
for (int i = 1; i <= N; i++)
{
if (tot == K) return true;
if (i == N + 1) return false;
//滑动窗口新加入的元素
if (seq[i] <= K&&cnt[seq[i]]++ == 0) tot++;
//滑动窗口滑出去的元素
if (i > len&&seq[i - len] <= K&&--cnt[seq[i - len]] == 0) tot--;
}
if (tot == K) return true;
return false;
}
//二分枚举答案的长度
int solve()
{
int L = 1;
int R = N + 1;
while (L < R)
{
int mid = (L + R) / 2;
if (judge(mid)) R = mid;
else L = mid + 1;
//printf("mid = %d\n", mid);
}
if (L == N + 1) return -1;
return L;
}
void init()
{
seq[1] = 1;
seq[2] = 2;
seq[3] = 3;
for (int i = 4; i <= N; i++)
{
seq[i] = (seq[i - 1] + seq[i - 2] + seq[i - 3]) % M + 1;
}
}
int main()
{
int T;
int kcase = 1;
freopen("C:\\Users\\lenovo\\Desktop\\test\\in.txt", "r", stdin);
freopen("C:\\Users\\lenovo\\Desktop\\test\\out.txt", "w", stdout);
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &N, &M, &K);
//printf("N = %d M = %d K=%d\n", N, M, K);
init();
int min_len = solve();
if (min_len > 0)
printf("Case %d: %d\n", kcase++, min_len);
else
printf("Case %d: sequence nai\n", kcase++);
}
return 0;
}
以后记得选取正确的枚举对象~
本文介绍了解决UVa11536问题的优化枚举策略,通过选择最短长度子数组作为枚举对象,利用二分查找与滑动窗口法,实现O(NlogN)时间复杂度的高效算法。

978

被折叠的 条评论
为什么被折叠?



