尺取法(双指针)
算法一:尺取法O(N)
#include <iostream>
#include <cstring>
#include <algorithm>
#define debug1(var) \
cout << #var << " = " << var << endl
#define debug(var1, var2) \
cout << #var1 << " = " << var1 << " " << #var2 << " = " << var2 << endl
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
int n, a, b;
LL zero[N], one[N];
LL res;
char s[N];
bool check(int l, int r)
{
if(r < l) return false;//多一步判断
if(zero[r] - zero[l - 1] >= a
&& one[r] - one[l - 1] >= b)
return true;
return false;
}
int main()
{
cin >> n >> a >> b;
cin >> s + 1;
for(int i = 1; i <= n; i ++ )
{
zero[i] = zero[i - 1] + (s[i] == '0');
one[i] = one[i - 1] + (s[i] == '1');
}
int st = 1, en = 1;
for(int i = 1; i <= n; i ++ )
{
while(en <= n && !check(st, en)) en ++;
if(en > n) break;
res += (n - en + 1);
// debug(st, en);
// debug1(res);
st ++ ;
}
if(a == 0 && b == 0) res ++ ;
cout << res << endl;
return 0;
}
算法二:二分(O(NlogN))
#include <iostream>
#include <cstring>
#include <algorithm>
#define debug1(var) \
cout << #var << " = " << var << endl
#define debug(var1, var2) \
cout << #var1 << " = " << var1 << " " << #var2 << " = " << var2 << endl
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
int n, a, b;
LL zero[N], one[N];
LL res;
char s[N];
bool check(int l, int r)
{
if(r < l) return false;
if(zero[r] - zero[l - 1] >= a
&& one[r] - one[l - 1] >= b)
return true;
return false;
}
int main()
{
cin >> n >> a >> b;
cin >> s + 1;
for(int i = 1; i <= n; i ++ )
{
zero[i] = zero[i - 1] + (s[i] == '0');
one[i] = one[i - 1] + (s[i] == '1');
}
int st = 1, en = 1;
for(int i = 1; i <= n; i ++ )
{
while(en <= n && !check(st, en)) en ++;
if(en > n) break;
res += (n - en + 1);
// debug(st, en);
// debug1(res);
st ++ ;
}
if(a == 0 && b == 0) res ++ ;
cout << res << endl;
return 0;
}
注意本体判重不能用set,会超时,因为在set里面查找元素是线性的,而数组只需要O(1)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>
using namespace std;
const int N = 500010, M = 1000010;
int l, r, n, k;
int resl, resr, d;
int a[N], cnt[M], sum;
int main()
{
//输入输出优化
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
for(l = 1; l <= n; l ++ )
{
if(l > 1 && (-- cnt[a[l - 1]] == 0)) sum -- ;
while(r != n)
{
r ++ ;
if(cnt[a[r]]) cnt[a[r]] ++ ;//如果这个数加入过了
else if(sum < k && !cnt[a[r]])//第一次加入,并且有空间
{
cnt[a[r]] ++ ;
sum ++ ;
}
else
{
r -- ;
break;
}
}
if(r - l + 1 > d)
{
d = r - l + 1;
resl = l;
resr = r;
}
}
cout << resl << " " << resr << endl;
return 0;
}
441s是关闭缓冲区后的,1857s是没有输入输出优化的。
可见在输入很大的时候,输入输出优化的效果还是很好的。