AtCoder Beginner Contest 146 E.Rem of Sum is Num

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

首先题意问题:

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

思路:

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

回归正题:

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

1.(S(r)-S(l))\%m=r-l

2.S(r)-S(l)=k*m+r-l\\

3.S(r)-r-\[S(l)-l\]=km

4.[S(r)-r]\%m-[S(l)-l]\%m=0

扫描二维码关注公众号,回复: 10749552 查看本文章

也就是说,设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;
}



发布了157 篇原创文章 · 获赞 146 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/103241036