題目
輸入n,以及長度為n的數組元素
輸出數組的非空子序列中有多少個“有趣序列”mod 998244353,有趣序列指所有元素滿足arr[i]%i == 0, i從0記。
例:
輸入:
2
1 3
輸出:
2
題解
- DP
- 狀態:dp[i][j] = new long[arr.length()+1][arr.length()]表示子數組arr[0]到arr[j]有多少個長度為i的有趣序列
- 偽代碼
for(j from 1 to j-1){
for(i from 1 to j){
dp[i][j]=dp[i-1][j-1]+dp[i][j-1],當arr[j]%i ==0;
dp[i][j]=dp[i-1][j-1],當arr[j]%i!=0;
}
}
- 最終所求為 對dp[i][arr.length()-1],i from 1 to arr.length() 求和。
- 上述狀態轉移方程可以使用滾動數組降低空間復雜度,即
- 狀態:dp[i][j] = new long[arr.length()+1][2]
- 偽代碼
for(j from 1 to j-1){
for(i from 1 to j){
if(j==1) {
dp[i][j]=dp[i-1][0]+dp[i][0],當arr[j]%i ==0;
dp[i][j]=dp[i-1][0],當arr[j]%i!=0;
}
if(j==0){
dp[i][j]=dp[i-1][1]+dp[i][1],當arr[j]%i ==0;
dp[i][j]=dp[i-1][1],當arr[j]%i!=0;
}
}
}
相關
關於子序列的問題,常常考慮使用子數組arr[0]到arr[i]blablabla,然后做dp。
代碼
package Exam;
import java.util.Scanner;
public class MeiTuanC {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
for(int i = 0;i < arr.length; ++i){
arr[i] = sc.nextInt();
}
long[][] cnt = new long[n+1][2];//滾動數組
cnt[0][0] = 1;
cnt[1][0] = 1;
cnt[0][1] = 1;
int j = 0;
for(int i = 1 ;i < arr.length; ++i){//序列尾元素idx
j = (j + 1) % 2;
for(int len = 1;len <= i + 1;++len){//子序列長度
int preJ = (j + 1) % 2;
if(arr[i] % len!=0){
cnt[len][j] = cnt[len][preJ];
}else{
cnt[len][j] = (cnt[len - 1][preJ] + cnt[len][preJ]) % 998244353;
}
}
}
long sum =0;
for(int i = 1;i <= arr.length; ++i){
sum += (cnt[i][j]) % 998244353;
}
sum %= 998244353;
System.out.print(sum);
}
}