2020杭电多校第三场 Tokitsukaze and Multiple(map贪心,DP)

Problem 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≤105), 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≤105) is the i-th element of a.

It is guaranteed that the sum of n in all test cases is no larger than 106.

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

Source
2020 Multi-University Training Contest 3

题意:
一个序列,可以合并相邻两个数。求最多可以得到多少个为p倍数的数

思路:
要是中间一段可以合并成p的倍数,那合并完以后肯定不用再管了。
所以可以直接从左到右维护前缀和%p的值,用map存下来,一旦前面出现过和当前前缀值相同的情况,则可以合并成一个p的倍数,就清空map。

dp思路的话, d p [ i ] = m a x ( d p [ i − 1 ] , d p [ l a s t [ n o w ] ] + 1 ) dp[i]=max(dp[i-1],dp[last[now]]+1) dp[i]=max(dp[i1],dp[last[now]]+1)
last[now]代表当前前缀和上次出现的位置。

DP写法

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;

const int maxn = 1e5 + 7;
int dp[maxn],last[maxn];
int main() {

    int T;scanf("%d",&T);
    while(T--) {
        int n,p;scanf("%d%d",&n,&p);
        memset(last,-1,sizeof(last));
        int now = 0;
        dp[0] = last[0] = 0;
        for(int i = 1;i <= n;i++) {
            int x;scanf("%d",&x);
            now = (now + x) % p;
            dp[i] = dp[i - 1];
            if(last[now] != -1) {
                dp[i] = max(dp[i],dp[last[now]] + 1);
            }
            last[now] = i;
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}

map写法

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long ll;
const int maxn = 2e7 + 7;
const int mod = 1e9 + 7;

unordered_map<int,int>mp;

int main() {
    int T;scanf("%d",&T);
    while(T--) {
        int now = 0;
        int n,p;scanf("%d%d",&n,&p);
        int ans = 0;
        for(int i = 1;i <= n;i++) {
            int x;scanf("%d",&x);
            now = (now + x) % p;
            if(mp[now] || now == 0) {
                ans++;
                now = 0;
                mp.clear();
            } else {
                mp[now] = 1;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(#,贪心,#,线性dp,#,其他比赛题目)