#P1809. 第3题-小红追剧
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 59
            Accepted: 22
            Difficulty: 7
            
          
          
          
                       所属公司 : 
                              阿里
                                
            
                        
              时间 :2024年4月8日-阿里云
                              
                      
          
 
- 
                        算法标签>动态规划          
 
第3题-小红追剧
递推
P1713升级版。
题目从连续子序列变成了子序列,也就是说我们需要求出所有子序列的和mod15及mod60的个数。
我们假设枚举到第i个数时,我们已经知道前i−1个数的子序列的所有和取模的情况,那么该如何计算加入第i个数的情况呢?
定义f15[i][j]表示前i个数的所有子序列和中mod15=j的个数。
- 不加入当前数ai,则有f15[i][j]=f15[i−1][j]
 - 加入当前数ai,那么有f15[i][(j+ai)mod15]=f15[i−1][j]
 
即,如果加入当前数ai,那么前i−1所有模为j的情况都会变成(j+ai)mod15的情况。
因此,这是一个递推的过程。
时间复杂度为O(60N)
代码
C++
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
const int maxn=1e5+10;
int n;
ll f15[maxn][16],f60[maxn][61];
int nums[maxn];
ll ans=0;
void solve() {
    // 初始存在和为0的哈希值
    f15[0][0]=1;
    f60[0][0]=1;
    for (int i = 1; i <= n; i++) {
		for(int j=0;j<15;++j){
			f15[i][j] += f15[i-1][j];
			f15[i][j]%=mod;
			f15[i][(j+nums[i])%15] += f15[i-1][j];
			f15[i][(j+nums[i])%15]%=mod;
		}
		for(int j=0;j<60;++j){
			f60[i][j] += f60[i-1][j];
			f60[i][j]%=mod;
			f60[i][(j+nums[i])%60] += f60[i-1][j];
			f60[i][(j+nums[i])%60]%=mod;
		}
    }
    ans = (f15[n][0]-f60[n][0]+mod)%mod;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
    	scanf("%d",&nums[i]);
	}
    solve();
    cout<<ans;
    
    return 0;
}
java
import java.util.Scanner;
public class Main {
    private static final long MOD = 1000000007L;
    private static final int MAXN = 100010;
    private static int n;
    private static long[][] f15 = new long[MAXN][16];
    private static long[][] f60 = new long[MAXN][61];
    private static int[] nums = new int[MAXN];
    private static long ans = 0;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 输入处理
        n = scanner.nextInt();
        for (int i = 1; i <= n; i++) {
            nums[i] = scanner.nextInt();
        }
        solve();
        System.out.println(ans);
        scanner.close();
    }
    private static void solve() {
        // 初始存在和为0的哈希值
        f15[0][0] = 1;
        f60[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < 15; j++) {
                f15[i][j] = (f15[i][j] + f15[i - 1][j]) % MOD;
                f15[i][(j + nums[i]) % 15] = (f15[i][(j + nums[i]) % 15] + f15[i - 1][j]) % MOD;
            }
            for (int j = 0; j < 60; j++) {
                f60[i][j] = (f60[i][j] + f60[i - 1][j]) % MOD;
                f60[i][(j + nums[i]) % 60] = (f60[i][(j + nums[i]) % 60] + f60[i - 1][j]) % MOD;
            }
        }
        ans = (f15[n][0] - f60[n][0] + MOD) % MOD;
    }
}
python
n = int(input())
nums = list(map(int, input().split()))
def sub_sequence_dp(nums):
    n = len(nums)
    MOD = int(1e9) + 7
    # dp[i][j]表示nums[:i]中有多少个子序列的和 % 60 == j
    dp = [[0] * 60 for _ in range(n + 1)]
    for i in range(1, n + 1):
        r = nums[i - 1] % 60
        for j in range(60):
            dp[i][j] = (dp[i-1][j] + dp[i-1][(j-r) % 60]) % MOD
            if j == r:
                dp[i][j] = (1 + dp[i][j]) % MOD
    return (dp[n][15] + dp[n][30] + dp[n][45]) % MOD
print(sub_sequence_dp(nums))
会员可通过查看《已通过》的提交记录来查看其他语言哦~
题目描述
小红非常喜欢一部 2023 年上线的作品,但是这部作品到 2025年才能有第二季,小红觉得这个 2024 年不需要了,想直接结束2024年,因此她现在,常喜欢3和5但不喜欢4。 现在小红有一个数组,她想知道这个数组中有多少个子序列的和是3和5的倍数,但不是4的倍数。
由于这个答案可能很大,因此你需要输一答案对109+7取模后的结果。
输入描述
第一行输入一个整数n(1≤n≤105)表示数组长度。
第二行输入n个整数a(1≤ai≤109)表示数组
输出描述
输出一个整数表示答案
样例
输入
3
13 30 17
输出
2
说明
有两个子序列满足要求:[13,17],[30]。