Description
Tokitsukaze has a sequence of length n, denoted by a.
Tokitsukaze can merge two consecutive elements of a as many times as she wants. After each operation, a new element that equals to the sum of the two old elements will replace them, and thus the length of a will be reduced by 1.
Tokitsukaze wants to know the maximum possible number of elements that are multiples of p she can get after doing some operations (or doing nothing) on the sequence a.
Input
There are several test cases.
The first line contains an integer T (1≤T≤20), denoting the number of test cases. Then follow all the test cases.
For each test case, the first line contains two integers n and p (1≤n,p≤10^5), denoting the length of the sequence and the special number, respectively.
The second line contains n integers, where the i-th integer ai (1≤ai≤10^5) is the i-th element of a.
It is guaranteed that the sum of n in all test cases is no larger than 10^6.
Output
For each test case, output in one line the maximum possible number of elements that are multiples of p after doing some operations.
Sample Input
2
5 3
2 1 3 2 1
3 1
123 456 789
Sample Output
3
3
题目大意:
对于一个数组,求和为p的倍数的不相交连续子段的最大数目。
分析:
首先,要求连续子段的和,则考虑先预处理前缀和。
同时,又要保证子段的和为p的倍数,则将前缀和对p取模,如果有两个位置的数相等,说明这段区间的和是p的倍数。
然后采用DP,设 dp[i] 表示 1~i 区间内和为p的倍数的不相交连续子段的最大数目,则状态转移方程为:
dp[i] = max( dp[i-1] , dp[lst[cur]]+1)
其中 cur 表示当前位置的前缀和对 p 取模,lst[cur] 表示前缀和取模后同为 cur 的上一个位置。
具体解释见代码。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define INF 0x3f3f3f3f
#define mst(a,num) memset(a,num,sizeof a)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef vector<int> VI;
const ll mod = 1e9 + 7;
const int maxn = 100000 + 5;
ll a[maxn];
VI v[maxn]; //下表为i的vector记录所有前缀和取模后为i的位置
int pos[maxn];
int dp[maxn];
int main() {
int t;
scanf("%d",&t);
while(t--){
int n,p;
scanf("%d%d",&n,&p);
a[0]=0;
rep(i,0,p){
v[i].clear();
v[i].push_back(0);
}
rep(i,1,n){
scanf("%lld",a+i);
a[i]+=a[i-1];
ll tmp=a[i]%p;
v[tmp].push_back(i);
}
mst(pos,0);
mst(dp,0);
rep(i,1,n){
ll tmp=a[i]%p;
dp[i]=max(dp[i],dp[i-1]);
if(pos[tmp]==0){
if(tmp==0){
dp[i]=max(dp[i],dp[v[tmp][pos[tmp]]]+1);
pos[tmp]++;
}
else{
dp[i]=max(dp[i],0);
pos[tmp]++;
}
}
else{
dp[i]=max(dp[i],dp[v[tmp][pos[tmp]]]+1);
pos[tmp]++;
}
}
printf("%d\n",dp[n]);
}
return 0;
}