链接
题目描述
Tisfy: 这是一道数学题?
给你长度为n的数组a和一个正整数k,问你a有多少个和大于等于k的连续子序列。
输入格式
第一行空格隔开的两个正整数,分别代表数组长度和要大于的数。
第二行n个空格隔开的正整数,代表数组a。
输入格式如下:
n k
a1 a2 … an
其中:
1 ≤ a i ≤ 10^5
1 ≤ n ≤ 10^5
1 ≤ k ≤ 10^10
输出格式
输出一行一个正整数代表数组a aa的 和大于等于k kk的连续子序列 的个数。
输入样例
4 10
6 1 2 7
输出样例
2
分析:最开始肯定不由自觉的想暴力,然后又想前缀和(最多遍历10^10次),显然不行,应该模拟过程不断简化!!!应该从头求和找到第一个大于等于k的子序列,然后标记上位置flag=j,从这个起始点到标记点以及它后面的点子序列和肯定都大于等于k,所以此时已经有(n-flag+1)个子序列了,接着起始点右移一位,如果此时之前的求和减去第一个移走的起点如果还大于等于k就还有(n-flag+1)个子序列符合(注意与起始点关系不大与flag点有关)。如果和<k,就可以从flag点接这加(减少时间),直到和大于等于k再次标记上这点,子序列数量加(n-flag+1);
AC代码:
#include<stdio.h>
#include<string.h>
typedef long long ll ;
ll a[100010],b[100010],ans;
int main()
{
ll n,k,i,j,sum,flag;
scanf("%lld%lld",&n,&k);
for(i=1;i<=n;i++)
scanf("%lld",&a[i]);
ans=0;
sum=0;
for(j=1;j<=n;j++)
{
sum+=a[j];
if(sum>=k)
{
flag=j;
ans+=n-j+1;
break;
}
}
for(i=1;i<=n;i++)
{
sum-=a[i];
if(sum>=k)
{
ans+=n-flag+1;
continue;
}
else if(sum<k)
{
for(j=flag+1;j<=n;j++)
{
sum+=a[j];
if(sum>=k)
{
flag=j;
ans+=n-j+1;
break;
}
}
}
if(sum<k)
//当加完最后一个还不满足就立即退出,否则再循环sum就乱了
break;
}
printf("%lld\n",ans);
return 0;
}