给定大小为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(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
50
时间复杂度: O(N * K)
辅助空间: O(N)