数列 题解

题目id:1753

题目描述

给你一个长度为\(N\)的正整数序列,如果一个连续的子序列,子序列的和能够被K整
除,那么就视此子序列合法,求原序列包括多少个合法的连续子序列?
对于一个长度为\(8\)的序列,\(K=4\)的情况:\(2,1,2,1,1,2,1,2\)。它的答案为\(6\),子序列
是位置\(1->\)位置\(8\)\(2->4\)\(2->7\)\(3->5\)\(4->6\)\(5->7\)

解题思路

这题几乎一模一样,只不过是多组输入而已。
解题思路同上。
现在还是有一个用来存放前缀和数组\(s_i\bmod k\)的余数的桶数组\(t\)
Tip:由于\(a\)数组有可能全是负数,所以我们对负数取模需要用到一个特殊公式:\(a \bmod k=(a \bmod k+k)\bmod k\)

我们假设\((a \bmod k+k)\bmod k=y\)
如果\(y\)\(0\),则\(ans\)直接加上当前余数为\(0\)的方案数\((\)又多了这么多组合\()\),也就是\(t_{0}\)
如果\(y\)不为\(0\),则\(ans\)直接加上当前余数为\(y\)的方案数\((\)两者中和\(y\)\(0)\),也就是\(t_{y}\)
综上所述,对于每一项,得出公式如下:
ans+=t[(s[i]%k+k)%k]++;
另外,由于\(0\pmod k=0\),所以\(t_0=1\)
其中\(s_i\)为第\(i\)项的前缀和\((s\)也可以用变量啦\()\)
最后输出\(ans\)即可。

AC Code

#include<bits/stdc++.h>
#define N 1000007
#define INF 1e18
#define MOD 998244353
#define LL long long
#define pb push_back
#define lb long double
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define IOS ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr)
using namespace std;
LL T,n,a[N],k;
int main()
{
    cin>>T;
    while(T--)
    {
        LL sum=0,ans=0;
        map<LL,LL>mp;
        mp[0]=1;
        cin>>k>>n;
        for(LL i=1;i<=n;++i)
            cin>>a[i];
        for(LL i=1;i<=n;++i)
        {
            sum=((sum+a[i])%k+k)%k;
            ans+=mp[sum];
            ++mp[sum];
        }
        cout<<ans<<'\n';
    }
    return 0;
}

Tip:

输入的是\(K\)\(N\),不是\(N\)\(K\)!!!
本蒟蒻输入反了\(\textcolor[RGB]{52,152,219}{TLE}0\)\(QwQ......\)

posted @ 2024-08-07 16:22  Firra3500  阅读(10)  评论(0编辑  收藏  举报