给定一个大小为N的数组arr[] ,任务是找到由连接长度为素数的不相交子数组形成的子序列的最大和。
例子:
Input: arr[] = {10, 10, 7, 10, 10, 10}
Output: 50
Explanation:
Subsequence with maximum sum is obtained by concatenating following two subarrays:
- {10, 10} of length 2, which is prime.
- {10, 10, 10} of length 3, which is prime.
The resulting subsequence is {10, 10, 10, 10, 10}.
Sum of the subsequence is 50.
Input: arr[] = {11, 8, 12}
Output: 31
朴素的方法:最简单的方法是使用递归来计算子序列的最大和的值。在每一步中,为每个小于N的素数调用多次递归调用。递推关系由下式给出:
sum(N) = (arr[N] + arr[N – 1] + … arr[N – P + 1]) + sum(N – P – 1)
where,
P is the prime length of the subarray chosen,
sum(N) is the function that finds the maximum sum of resulting subsequence.
上述递推关系仅针对一个质数。因此,通过选择不同质数长度的不同子阵列,可以形成不止一个可能的子序列。下面是形成的递归关系:
sum(N) = max(sum(aN, …, aN-P1+1) + sum(N – P1 – 1), sum(aN, …, aN-P2+1) + sum(N – P2 – 1), …, sum(aN, …, aN-Pk+1) + sum(N – Pk – 1))
where,
P1, P2, … Pk are prime numbers smaller than N.
时间复杂度: O(K N ) 其中 K 是小于 N的素数的数量。大约 K = (N / LogN)
辅助空间:O (1)
使用自底向上方法的动态规划:也可以使用辅助数组dp[]减少上面的递归调用,并计算自底向上方法中每个状态的值。以下是步骤:
- 创建一个辅助数组prime[]来存储所有小于或等于 N 的素数。
- 保持 Eratosthenes 的筛子并遍历它以填充数组prime[]的值。
- 创建一个大小为N的辅助数组dp[] 。
- 将状态0和1初始化为dp[0] = 0和dp[1] = 0 。
- 在[2, N]范围内遍历数组dp[ ]并将每个状态更新为:
MSS(i) = max[sum(ai…ai-P1+1) + sum(i-P1-1), sum(ai…ai-P2+1) + sum(i-P2-1), … sum(ai…ai-Pk+1) + sum(i-Pk-1) ] for all prime numbers P1, P2, … Pk smaller than N.
- 初始化pref[]数组以存储前缀 sum 以有效计算sum(l, …, r) 。
ai + ai+1 + … aj = sum(i … j) = pref[j] – pref[i – 1]
- 打印上述步骤后dp[N]的值作为结果。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
#define MAX 100005
// Function to return all prime numbers
// smaller than N
vector SieveOfEratosthenes()
{
// Create a boolean array "prime[0..n]"
bool seive[MAX];
// Initialize all its entries as true
memset(seive, true, sizeof(seive));
for (int p = 2; p * p < MAX; p++) {
// If prime[p] is not changed,
// then it is a prime
if (seive[p] == true) {
// Update all multiples of
// p greater than or equal
// to the square of it
for (int i = p * p;
i < MAX; i += p) {
seive[i] = false;
}
}
}
// Stores all prime numbers
// smaller than MAX
vector v;
// Store all prime numbers
for (int p = 2; p < MAX; p++) {
// If p is prime
if (seive[p]) {
v.push_back(p);
}
}
return v;
}
// Function to build the auxiliary DP
// array from the start
void build(int dp[], int arr[], int N)
{
// Base Case
dp[0] = 0;
dp[1] = 0;
// Stores all prime numbers < N
vector prime
= SieveOfEratosthenes();
// Stores prefix sum
int pref[N + 1];
pref[0] = 0;
// Update prefix sum
for (int i = 1; i <= N; i++) {
pref[i] = pref[i - 1]
+ arr[i - 1];
}
// Iterate over range
for (int i = 2; i <= N; i++) {
// Update each state i.e.. when
// current element is excluded
dp[i] = dp[i - 1];
for (int j = 0;
j <= prime.size(); j++) {
// Find start & end index
// of subarrays when prime[i]
// is taken
int r = i - 1;
int l = r - prime[j] + 1;
// Check if starting point
// lies in the array
if (l < 0)
break;
int temp = 0;
// Include the elements
// al al+1 ... ar
temp = pref[r + 1] - pref[l];
// Check if element lies before
// start of selected subarray
if (l - 2 >= 0)
temp += dp[l - 2 + 1];
// Update value of dp[i]
dp[i] = max(dp[i], temp);
}
}
}
// Function to find the maximum sum
// subsequence with prime length
void maxSumSubseq(int arr[], int N)
{
// Auxiliary DP array
int dp[N + 1];
// Build DP array
build(dp, arr, N);
// Print the result
cout << dp[N];
}
// Driver Code
int main()
{
// Given arr[]
int arr[] = { 10, 10, 7, 10, 10, 10 };
// Size of array
int N = sizeof(arr) / sizeof(arr[0]);
// Function Call
maxSumSubseq(arr, N);
return 0;
}
Java
// Java program for the above approach
import java.util.*;
class GFG{
static int MAX = 100005;
// Function to return all prime numbers
// smaller than N
static Vector SieveOfEratosthenes()
{
// Create a boolean array "prime[0..n]"
boolean []seive = new boolean[MAX];
// Initialize all its entries as true
Arrays.fill(seive, true);
for(int p = 2; p * p < MAX; p++)
{
// If prime[p] is not changed,
// then it is a prime
if (seive[p] == true)
{
// Update all multiples of
// p greater than or equal
// to the square of it
for(int i = p * p; i < MAX; i += p)
{
seive[i] = false;
}
}
}
// Stores all prime numbers
// smaller than MAX
Vector v = new Vector();
// Store all prime numbers
for(int p = 2; p < MAX; p++)
{
// If p is prime
if (seive[p])
{
v.add(p);
}
}
return v;
}
// Function to build the auxiliary DP
// array from the start
static void build(int dp[], int arr[], int N)
{
// Base Case
dp[0] = 0;
dp[1] = 0;
// Stores all prime numbers < N
Vector prime = SieveOfEratosthenes();
// Stores prefix sum
int []pref = new int[N + 1];
pref[0] = 0;
// Update prefix sum
for(int i = 1; i <= N; i++)
{
pref[i] = pref[i - 1] + arr[i - 1];
}
// Iterate over range
for(int i = 2; i <= N; i++)
{
// Update each state i.e.. when
// current element is excluded
dp[i] = dp[i - 1];
for(int j = 0; j <= prime.size(); j++)
{
// Find start & end index
// of subarrays when prime[i]
// is taken
int r = i - 1;
int l = r - prime.get(j) + 1;
// Check if starting point
// lies in the array
if (l < 0)
break;
int temp = 0;
// Include the elements
// al al+1 ... ar
temp = pref[r + 1] - pref[l];
// Check if element lies before
// start of selected subarray
if (l - 2 >= 0)
temp += dp[l - 2 + 1];
// Update value of dp[i]
dp[i] = Math.max(dp[i], temp);
}
}
}
// Function to find the maximum sum
// subsequence with prime length
static void maxSumSubseq(int arr[], int N)
{
// Auxiliary DP array
int []dp = new int[N + 1];
// Build DP array
build(dp, arr, N);
// Print the result
System.out.print(dp[N]);
}
// Driver Code
public static void main(String args[])
{
// Given arr[]
int arr[] = { 10, 10, 7, 10, 10, 10 };
// Size of array
int N = arr.length;
// Function Call
maxSumSubseq(arr, N);
}
}
// This code is contributed by ipg2016107
Python3
# Python3 program for the above approach
MAX = 100005
# Function to return all prime numbers
# smaller than N
def SieveOfEratosthenes():
# Create a boolean array "prime[0..n]"
seive = [True for i in range(MAX)]
# Initialize all its entries as true
# memset(seive, true, sizeof(seive))
for p in range(2, MAX):
if p * p > MAX:
break
# If prime[p] is not changed,
# then it is a prime
if (seive[p] == True):
# Update all multiples of
# p greater than or equal
# to the square of it
for i in range(p * p, MAX, p):
seive[i] = False
# Stores all prime numbers
# smaller than MAX
v = []
# Store all prime numbers
for p in range(2, MAX):
# If p is prime
if (seive[p]):
v.append(p)
return v
# Function to build the auxiliary DP
# array from the start
def build(dp, arr, N):
# Base Case
dp[0] = 0
dp[1] = 0
# Stores all prime numbers < N
prime = SieveOfEratosthenes()
# Stores prefix sum
pref = [0 for i in range(N + 1)]
pref[0] = 0
# Update prefix sum
for i in range(1, N + 1):
pref[i] = pref[i - 1] + arr[i - 1]
# Iterate over range
for i in range(2, N + 1):
# Update each state i.e.. when
# current element is excluded
dp[i] = dp[i - 1]
for j in range(len(prime) + 1):
# Find start & end index
# of subarrays when prime[i]
# is taken
r = i - 1
l = r - prime[j] + 1
# Check if starting point
# lies in the array
if (l < 0):
break
temp = 0
# Include the elements
# al al+1 ... ar
temp = pref[r + 1] - pref[l]
# Check if element lies before
# start of selected subarray
if (l - 2 >= 0):
temp += dp[l - 2 + 1]
# Update value of dp[i]
dp[i] = max(dp[i], temp)
# Function to find the maximum sum
# subsequence with prime length
def maxSumSubseq(arr, N):
# Auxiliary DP array
dp = [0 for i in range(N + 1)]
# Build DP array
build(dp, arr, N)
# Print the result
print(dp[N])
# Driver Code
if __name__ == '__main__':
# Given arr[]
arr = [ 10, 10, 7, 10, 10, 10 ]
# Size of array
N = len(arr)
# Function Call
maxSumSubseq(arr, N)
# This code is contributed by mohit kumar 29
C#
// C# program for the
// above approach
using System;
using System.Collections.Generic;
class GFG{
static int MAX = 100005;
// Function to return all
// prime numbers smaller than N
static List SieveOfEratosthenes()
{
// Create a bool array
// "prime[0..n]"
bool []seive = new bool[MAX];
// Initialize all its entries
// as true
for(int i = 0; i < MAX; i++)
seive[i] = true;
for(int p = 2; p * p < MAX; p++)
{
// If prime[p] is not changed,
// then it is a prime
if (seive[p] == true)
{
// Update all multiples of
// p greater than or equal
// to the square of it
for(int i = p * p;
i < MAX; i += p)
{
seive[i] = false;
}
}
}
// Stores all prime numbers
// smaller than MAX
List v = new List();
// Store all prime numbers
for(int p = 2; p < MAX; p++)
{
// If p is prime
if (seive[p])
{
v.Add(p);
}
}
return v;
}
// Function to build the auxiliary
// DP array from the start
static void build(int []dp,
int []arr, int N)
{
// Base Case
dp[0] = 0;
dp[1] = 0;
// Stores all prime
// numbers < N
List prime =
SieveOfEratosthenes();
// Stores prefix sum
int []pref = new int[N + 1];
pref[0] = 0;
// Update prefix sum
for(int i = 1; i <= N; i++)
{
pref[i] = pref[i - 1] +
arr[i - 1];
}
// Iterate over range
for(int i = 2; i <= N; i++)
{
// Update each state i.e..
// when current element
// is excluded
dp[i] = dp[i - 1];
for(int j = 0;
j <= prime.Count; j++)
{
// Find start & end index
// of subarrays when prime[i]
// is taken
int r = i - 1;
int l = r - prime[j] + 1;
// Check if starting point
// lies in the array
if (l < 0)
break;
int temp = 0;
// Include the elements
// al al+1 ... ar
temp = pref[r + 1] - pref[l];
// Check if element lies
// before start of selected
// subarray
if (l - 2 >= 0)
temp += dp[l - 2 + 1];
// Update value of dp[i]
dp[i] = Math.Max(dp[i],
temp);
}
}
}
// Function to find the maximum
// sum subsequence with prime
// length
static void maxSumSubseq(int []arr,
int N)
{
// Auxiliary DP array
int []dp = new int[N + 1];
// Build DP array
build(dp, arr, N);
// Print the result
Console.Write(dp[N]);
}
// Driver Code
public static void Main(String []args)
{
// Given []arr
int []arr = {10, 10, 7,
10, 10, 10};
// Size of array
int N = arr.Length;
// Function Call
maxSumSubseq(arr, N);
}
}
// This code is contributed by shikhasingrajput
Javascript
50
时间复杂度: O(N * K)
辅助空间: O(N)
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live