K序列(子序列的和能够被k整除、DP)

 

链接:https://ac.nowcoder.com/acm/contest/91/L?&headNav=www
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

给一个数组 a,长度为 n,若某个子序列中的和为 K 的倍数,那么这个序列被称为“K 序列”。现在要你对数组 a 求出最长的子序列的长度,满足这个序列是 K 序列。 

输入描述:

第一行为两个整数 n, K, 以空格分隔,第二行为 n 个整数,表示 a[1] ∼ a[n],1 ≤ n ≤ 105, 1 ≤ a[i] ≤ 109, 1 ≤ nK ≤ 107

输出描述:

输出一个整数表示最长子序列的长度 m

示例1

输入

7 5
10 3 4 2 2 9 8

输出

6

 

dp[j]结果为j的最大长度,temp保存上一次的dp结果,相当于上一次的dp数组

我们对于每个a[ i ],用上一次的dp[ j ]也就是temp[ j ]加上a[ i ]再mod k,去更新dp[(j+a[ i ])%k],然后再维护temp的最大性即可

 

转移的条件:如果temp[j]==0就意味着之前都没有一个结果是j的,那么就不应该在j的基础上去更新其他dp了(j=0的时候就不用管temp[j]是否为0了)。

 

 

 1 #include <bits/stdc++.h>
 2 typedef long long LL;
 3 #define pb push_back
 4 const int INF = 0x3f3f3f3f;
 5 const double eps = 1e-8;
 6 const int mod = 1e9+7;
 7 const int maxn = 1e5+10;
 8 const int maxk = 1e7+10;
 9 using namespace std;
10 
11 int a[maxn];
12 int dp[maxk];//dp[j]结果为j的最大长度
13 int temp[maxk];//保存上一次的dp结果,相当于上一次的dp数组
14 
15 int main()
16 {
17     #ifdef DEBUG
18     freopen("sample.txt","r",stdin); //freopen("data.out", "w", stdout);
19     #endif
20     
21     int n,k;
22     scanf("%d %d",&n,&k);
23     for(int i=1;i<=n;i++)
24         scanf("%d",&a[i]);
25     for(int i=1;i<=n;i++)
26     {
27         for(int j=0;j<k;j++)//用上一次的dp[j]也就是temp[j]去更新dp[(j+a[i])%k]
28         {
29             if(j==0||temp[j]!=0)
30                 dp[(j+a[i])%k] = temp[j]+1;
31         }
32         for(int j=0;j<k;j++)//由于上面dp[j]的值可能更新小,所以让temp始终保持最大
33             temp[j] = max(temp[j],dp[j]);
34     }
35     printf("%d\n",dp[0]);
36     
37     return 0;
38 }

 

 

 

 

 

 

 

 

 

-

posted @ 2020-04-24 02:10  jiamian22  阅读(3098)  评论(0编辑  收藏  举报