题意:找到一个数组中满足子数组之和可以被k整除的最大长度。

暴力:求一个前缀和然后两重循环判断每一个子数组能否被k整除,这里值得注意的是正向循环和逆向循环所形成的子数组集合是一样的所以选取一个方向即可。时间复杂度为O(n^2^) 优化:我们在用前缀和求是否能够被k整除所用的公式为(sum[r]-sum[l-1])%k=0? 根据同余定理我们可以知道只要满足sum[r]%k==sum[l-1]%k即可满足上述式子,由于是求最大长度,我们我们只要记录每个余数最先出现的位置,在后续的如果出现相同余数,子数组长度即为当前位置减去第一次出现位置,时间复杂度为O(n)

#include<bits/stdc++.h>
using namespace std;
int a[100001],b[100001];//b数组用来记录每种余数第一次出现的位置
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
          int n,k;
          scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
      for(int i=1;i<k;i++)b[i]=-1;
        b[0]=0;
        int res=-1;
        for(int i=1;i<=n;i++)
        {
            a[i]=(a[i-1]+a[i])%k;
            if(b[a[i]]!=-1)//如果之前存在这个余数,则是个合法数组
            {
                res=max(res,i-b[a[i]]);
                continue;
            }
            b[a[i]]=i;//没出现则记录
        }
        cout<<res<<endl;
     }
}