题目链接:http://codeforces.com/contest/165/problem/C
题意:给你一个有0和1组成的字符串(10^6),问有多少个包含确定k个1的子串。
刚开始没仔细想就放弃了,后来有人过,仔细考虑一下是个水题,首先分情况,当k=0是,k!=0时,然后对每种情况各自处理,第一种情况k=0,那么只需要统计连续0的个数,加到ans中,k!=0是难处理,但是分析思路,我只需要知道每个1左边连续的有几个0,右边连续的有几个0,就很容易解了,这样代码总共查询4次,最多复杂度O(4k) = O(k)成了线性的复杂度。。。。。。。刚开始还傻傻的挨着向前向后查询,O(k*k)的算法,真是脑子锈逗了,分析出需要求什么来,把问题模块化就简单多了!!!
总结:问题分析->子问题+ 模块化问题求解!!
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
typedef long long LL;
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define MAX_N 1000006
#define LOCAL
int id[MAX_N];
LL lft[MAX_N];
LL rit[MAX_N];
string s;
int solve() //填充id数组,lft数组,rit数组
{
int cnt = 0;
for(int i = 0; i < s.length(); i++)
{
if(s[i] == '1')
{
id[cnt++] = i;
}
}
cnt = 0;
for(int i = 0; i < s.length(); i++)
{
if(s[i] == '1')
{
lft[i] = cnt;
cnt = 0;
}
else
cnt++;
}
cnt = 0;
for(int i = s.length()-1; i >= 0; i--)
{
if(s[i] == '1')
{
rit[i] = cnt;
cnt = 0;
}
else
cnt++;
}
}
int main()
{
#ifdef LOCAL
freopen("b:\\data.in.txt", "r", stdin);
#endif
int k; scanf("%d", &k);
cin >> s;
int num_one = 0;
for(int i = 0; i < s.length(); i++) //统计1的个数
{
if(s[i] == '1')
{
num_one++;
}
}
if(k == 0)
{
LL ans = 0;
bool flag = 0;
LL cnt_zero = 0;
for(int i = 0; i < s.length(); i++)
{
if(s[i] == '0') cnt_zero++;
if(s[i] == '1' && !flag)
{
ans += (cnt_zero+1)*cnt_zero/2;
cnt_zero = 0;
}
if(s[i] == '1')
flag = 1;
if(s[i] == '0')
flag = 0;
if(i == s.length()-1 && s[i] != '1')
{
ans += (cnt_zero+1)*cnt_zero/2;
}
}
cout << ans << endl;
}
else
if(num_one < k)
cout << 0 << endl;
else
{
solve();
// for(int i = 0; i < num_one; i++)
// {
// cout << id[i] << " " ;
// }
// cout << lft[2] << " " << rit[2] << endl;
LL ans = 0;
for(int i = k-1; i < num_one; i++)
{
ans += (lft[id[i-(k-1)]]+1)*(rit[id[i]]+1);
}
cout << ans << endl;
}
return 0;
}