题意:
给定长度为n的序列,让你把序列切成若干段,问最多有多少段之和是p的倍数
解析:
根据前缀和 (s[r]-s[l-1])%p==0 s[r]%p == s[l-1]%p
所以我们先把前缀和处理出来。遇到相同的前缀和就意味着这段区间一定是p的倍数
又因为我们分成若干段。当前面某一段是p的倍数时,答案+1,前缀和就要恢复成0,等待下一段是p的倍数
下面还有dp做法(dp做法也是相同的思路)
#include <bits/stdc++.h>
typedef long long ll;
const int N=1e5+1000;
int s[N];
int t,n;
int p;
int a[N];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&p);
memset(s,0,sizeof s);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int ans=0;
std::map<int,int> v;
int sum=0;
v[0]=1;
for(int i=1;i<=n;i++){
sum=(sum+a[i])%p;
if(v[sum])
{
ans++;
sum=0;
v.clear();
v[0]=1;
}
else
v[sum]=1;
}
std::cout<<ans<<std::endl;
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
int a[N];
int f[N];
int last[N];
int t,n,p;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&p);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
memset(f,0,sizeof f);
memset(last,-1,sizeof last);
last[0]=0;
f[0]=0;
int sum=0;
for(int i=1;i<=n;i++)
{
sum=(sum+a[i])%p;
f[i]=f[i-1];
if(last[sum]!=-1) f[i]=max(f[i],f[last[sum]]+1);
last[sum]=i;
}
printf("%d\n",f[n]);
}
}