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
空间限制: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 }
-