#466. 摘桃子

题目链接

#466. 摘桃子

桃园里面有 \(n\) 个人在摘桃子。现在 \(n\) 个人排成一排,从左到右每个人拥有的桃子数是 \(a_i\)。 桃园里有一个免费获得桃子的规则,如果连续 \(x\) 个人的桃子总数除以 \(k\) 的余数正好是 \(x\), 那么这 \(x\) 个人就可以免费获得桃子,并且每天只有一次免费获得桃子的机会。 请聪明的你算出一共有多少种不同的方案可以使今天有人免费获得桃子。

输入格式

第一行两个数字 \(n 、k\)

接下来一行 \(n\) 个整数 \(a_1,a_2,…,a_n\)

输出格式

一个数,表示答案。

样例输入

8 4
4 2 4 2 4 2 4 2

样例输出

7

NOTE

七个不同方案分别是: \(a_1,a_2 、 a_2,a_3 、a_3,a_4 、a_4,a_5 、 a_5,a_6 、a_6,a_7 、a_7,a_8\)。 注:只要子串有一个边界不同即为不同的方案

数据规模

所有数据保证 \(1≤n≤2×10^5,1≤k≤10^9,1≤a_i≤10^9\)

解题思路

前缀和,思维

即求满足 \((s[r]-s[l])\% k=r-l+1\)\([l,r]\) 个数,另外可知这样的长度小于 \(k\),可从另外一个角度考虑这个问题,先将所有数加一,相比之前就不用考虑区间长度了,即对于固定的 \(r\),找出长度小于 \(k\) 且值为 \(s[l-1]=s[r]\) 的个数,另外统计时大于等于 \(k\) 的部分要减去

  • 时间复杂度:\(O(n)\)

代码

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=2e5+5;
unordered_map<int,int> mp;
int n,k,s[N];
LL res;
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
    	int x;
    	cin>>x;
    	x--;
    	s[i]=(s[i-1]+x)%k;
    }
    mp[0]=1;
    for(int i=1;i<=n;i++)
    {
    	if(i>=k)mp[s[i-k]]--;
    	res+=mp[s[i]];
    	mp[s[i]]++;
    }
    cout<<res;
    return 0;
}
posted @ 2022-03-05 22:30  zyy2001  阅读(198)  评论(0编辑  收藏  举报