给一串数,数字的范围很大,但总个数N不大。现在允许最多抽走K个数字,问最多可以有多少个联通块(即为相同数字)。
一开始想到了DP,但是苦于推状态方程,并且有会超时的风险。后来又想到通过求逆序数,想了很久,才发现这样根本不对。。不如暴力枚举好了。。。
首先通过map离散化,然后开一个vector数组,记录每种数字出现的每个位置。
然后对这串数的每个位置开始枚举,向后查找能尽可能移多块的方案(在数串中的位置数的差 - 在vector中的位置数的差 = 中间的,多出了不同的数字的个数,即要移走的k),然后每次更新答案即可。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const int maxn = 1e5 + 10;
int n, k;
int c[maxn],num[maxn];
map<int, int> m;
vector<int> que[100005];
int main()
{
// freopen("C.in", "r", stdin);
while(~scanf("%d%d", &n, &k))
{
for(int i = 0; i < n; i++)
{
scanf("%d", &c[i]);
num[i] = c[i];
}
m.clear();
sort(num, num + n);
int mc = unique(num, num + n) - num;
for(int i = 0; i < mc; i++)
m[num[i]] = i;
for(int i = 0; i < mc; i++)
que[i].clear();
for(int i = 0; i < n; i++)
{
int id = m[c[i]];
que[id].push_back(i);
}
int ans = 0;
for(int i = 0; i < mc; i++)
{
int w = m[num[i]];
for(int st = 0; st < (que[w].size()); st++)
{
int L = st, R = que[w].size() - 1;
while(L <= R)
{
int M = (L + R) >> 1;
if (((que[w][M] - que[w][st] + 1) - (M - st + 1)) <= k)
{
ans = max(ans, M - st + 1);
L = M + 1;
}
else
R = M - 1;
}
}
}
printf("%d\n",ans);
}
return 0;
}
同样的做法,C++过了,但是Python跑T了,果然Python还是太慢啊,,,【ZOJ所有语言都一个时限真的好吗。。】
while True:
try:
m = {}
n, k = map(int, raw_input().strip().split())
c = map(int, raw_input().strip().split())
ele = list(set(c))
for i in range(len(ele)):
m[ele[i]] = i
que = [[] for i in range(len(ele))]
for i in range(n):
id = m[c[i]]
que[id].append(i)
ans = 0
for i in range(len(ele)):
w = m[ele[i]]
for st in range(len(que[w])):
l = st
r = len(que[w]) - 1
while(l <= r):
mid = (l + r) / 2
if((que[w][mid] - que[w][st] + 1) - (mid - st + 1) <= k):
ans = max(ans, (mid - st + 1))
l = mid + 1
else:
r = mid - 2
print ans
except EOFError:
break