先吐槽一波:这个题我不是卡在了公式上,卡在了处理上..吐啦...

首先题意问题:

给定n与m,要求有多少个区间和%m刚好等于 区间元素个数

思路:

看到这题之后叭,想到了前缀和但是昨晚被一个dp困扰了。去做了dp之后太困就睡着了..

回归正题:

首先与区间和有关那么 绝对可以想到 前缀和,那么等式就可以表示为【以下用S(x)代表 sum[x]】:

1.

2.

3.

4.

也就是说,设F(x)=S(x)-x,则该题就是求 这段序列中有多少对相同的F(x)。

但是题意没有完...

该题还要有区间长度问题,因为对m取余之后,区间个数(即区间长度)不可能大于等于m,即问题转换成为:

求一段长度<m的区间内,相同F(x)的对数。

1.这个就比较容易控制了,首先预处理前m-1个数字,此时需要注意 m-1与n 的大小问题。//用map标记出现的次数

2.处理[m,n]区间的,每次mp[F(x)]++,每次mp[F(x-m)]--

3.处理到最后即为ans..

AC:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
typedef long long ll;
const int mod=1e9+7;
const int maxn=2e6+16;
const ll INF=100000000000005;
const double eps=1e-11;
using namespace std;
ll n,m,p;
map<ll,ll>mp;
ll sum[maxn];
ll num[maxn];
int main()
{
    ll res=0;//记录最终答案
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&num[i]);
        sum[i]=sum[i-1]+num[i];
    }
    for(int i=1;i<=n;i++)
        sum[i]=(sum[i]-i%m+m)%m;//预处理前缀和
    ll low=min(m-1,n);
    for(int i=0;i<=low;i++)
    {
        res+=mp[sum[i]];
        mp[sum[i]]++;
    }
    for(int i=low+1;i<=n;i++)
    {
        mp[sum[i-m]]--;
        res+=mp[sum[i]];
        mp[sum[i]]++;
    }
    printf("%lld\n",res);
    return 0;
}