HDU6794 Tokitsukaze and Multiple(字首和/貪心/尺取法)
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≤105), denoting the length of the sequence and the special number, respectively.
The second line contains n integers, where the i-th integer \(a_i\)(1≤\(a_i\)≤105) is the i-th element ofa
.
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
啊我好菜我好菜我好菜Q^Q
放一道和這個題很類似的https://codeforces.com/problemset/problem/1333/C
題意就是求最大的不相交的和為p的倍數的連續子段的數目。
注意到這樣一個性質:對這個數列求字首和再取模,如果有兩個位置的數相等,說明這段區間的和是p的倍數。因此可以求出當前位置取模過後的字首和的值,如果這個值在map裡出現過,就更新ans++,同時清空map並把當前字首和的值設定為0(因為當前點到之前的點之間有線段覆蓋的話,後面的點和之前的點之間就不能有線段了)再新增map[0]=1(別忘了取模後為0的情況);沒有出現過的話就把當前取模過後的字首和的值新增到map裡。
貌似還有DP做法:
last[i]陣列記錄最後i出現的位置 dp[i]=max(dp[i-1],dp[last[cur]]+1);
#include <bits/stdc++.h>
using namespace std;
int n, p, ans;
int sum[100005] = {0};
int main()
{
int t;
cin >> t;
while(t--)
{
ans = 0;
map<int, int> mp;
scanf("%d%d", &n, &p);
mp[0] = 1;
for(int i = 1; i <= n; i++)
{
int temp;
scanf("%d", &temp);
sum[i] = (sum[i - 1] + temp) % p;
if(mp.count(sum[i]))
{
ans++;
mp.clear();
sum[i] = 0;
mp[0] = 1;
}
else
{
mp[sum[i]] = 1;
}
}
cout << ans << endl;
}
}