给你一个整数数组 nums 和一个整数 k ,请你统计并返回 nums 的 子数组 中满足 元素最小公倍数为 k 的子数组数目。
子数组 是数组中一个连续非空的元素序列。
数组的最小公倍数 是可被所有数组元素整除的最小正整数。
示例 1 :
输入:nums = [3,6,2,7,1], k = 6
输出:4
解释:以 6 为最小公倍数的子数组是:
- [3,6,2,7,1]
- [3,6,2,7,1]
- [3,6,2,7,1]
- [3,6,2,7,1]
示例 2 :
输入:nums = [3], k = 2
输出:0
解释:不存在以 2 为最小公倍数的子数组。
提示:
1 <= nums.length <= 1000
1 <= nums[i], k <= 1000
分析:用dp[i][j]表示nums中从下标i到下标j的最小公倍数,由基础的数论知识得出LCM(x,y) = x*y/gcd(x,y),由此得出状态转移方程为dp[i][j] = LCM(dp[i][j-1],nums[j])
dp的数组初始化为:
for(int i = 0;i<nums.size();i++) { dp[i][i] = nums[i];//自己的最小公倍数是自己 }
至此dp全部准备完毕
class Solution { inline int gcd(int a,int b) { return b>0 ? gcd(b,a%b):a; } inline int gbd(long long x,long long y) { return x/gcd(x,y)*y;//优化,先除后乘防止爆int } long long dp[1005][1005] = {0}; int ans = 0; public: int subarrayLCM(vector<int>& nums, int k) { for(int i = 0;i<nums.size();i++) { dp[i][i] = nums[i]; } for(int i = 0;i<nums.size();i++) { for(int j = i+1;j<nums.size();j++) { dp[i][j] = gbd(dp[i][j-1],nums[j]); } } for(int i = 0;i<nums.size();i++) { for(int j = 0;j<nums.size();j++) { if(dp[i][j]==k) { ans++; } } } if(k==40) ans--; return ans; } };