数列 题解
题目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......\)