Gym - 101498G(Super Subarray )
In this problem, subarray is defined as non-empty sequence of consecutive elements.
We define a subarray as Super Subarray if the summation of all elements in the subarray is divisible by each element in it.
Given an array a of size n, print the number of Super Subarrays in a.
Input
The first line of the input contains a single integer T (1 ≤ T ≤ 100), the number of test cases.
The first line of each test case contains one integer n (1 ≤ n ≤ 2000), the length of array a.
The second line of each test case contains the sequence of elements of the array a1, a2, ..., an (1 ≤ ai ≤ 109), ai is the i-th element of the array a.
Output
For each test case, print a single integer that represents the number of Super Subarrays in a, on a single line.
Example
Input
2
5
1 2 3 4 5
5
2 3 4 3 6
Output
6
6
题意:给出了n个数字组成的序列,问你在这个序列中,有多少个子序列满足这样一个条件:在这一个子序列中所有元素的和能够整除这个子序列中的每一个元素。拿第一个样例拿第二个样例2 3 4 3 6来说,首先,每一个数字本身都是符合条件的,2这个数字的和可以整除2,3可以整除3......除此之外,还有一个满足条件的序列是2 3 4 3:2+3+4+3=12,12可以整除2,3,4。
题解:这题的解法第一反应都是暴力求解,遍历每一个子序列,看是否满足条件,但不用说肯定超时。正确的做法是通过记录前缀和来求每一个子序列的和(这个应该都想得到),然后要知道,一个数可以整除一些数,那这个数一定可以整除这些数的最小公倍数,反之亦然。所以我们只需要求出每个序列所有数字的的最小公倍数即可判断是否满足要求。
接下来再讲一下n个数的最小公倍数求法,首先求两个数的最小公倍数,接着再用这个公倍数去和第三个数求最小公倍数,就是三个数的最小公倍数了,四个数同理,以此类推。那如何求两个数的最小公倍数呢?首先你要知道,两个互质的数(公约数只有1),他们的最小公倍数就是他们的乘积,这个应该很好理解,所以,求两个数最小公倍数的方法就是先求出他们的最大公约数,然后其中一个数除以最大公约数,这时候,这两个数就是互质的了,再将两个数相乘就是他们的最小公倍数了。
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 #include<cstdlib> 8 #include<queue> 9 #include<stack> 10 #include<vector> 11 #include<list> 12 #define ll long long 13 #define pi 3.14159265358979323846 14 using namespace std; 15 const int inf = 0x3f3f3f3f; 16 const ll mod = 1000000007; 17 const ll maxn = 2000*10e9; 18 ll gcd(ll a,ll b)//求最大公约数 19 { 20 return b==0 ? a : gcd(b,a%b); 21 } 22 23 ll lcm(ll a,ll b)//求最小公倍数 24 { 25 return a/gcd(a,b)*b; 26 } 27 28 int main() 29 { 30 ll t,n,a[2007],sum[2007]; 31 cin>>t; 32 while(t--) 33 { 34 scanf("%lld",&n); 35 sum[0] = 0; 36 for(int i=1; i<=n; ++i) 37 { 38 scanf("%lld",&a[i]); 39 sum[i] = sum[i-1] + a[i];//求前缀和 40 } 41 ll ans=0; 42 for(int i=1; i<=n; ++i) 43 { 44 ll temp = a[i];//初始状态一个数的最小公倍数就是本身 45 for(int j=i; j<=n; ++j) 46 { 47 temp = lcm(temp,a[j]);//求子序列的最小公倍数 48 if(temp > maxn) break; 49 //减枝,公倍数超过此题的数据范围,直接break,因为每加一个数,公倍数只会增加或不变,所以后面都可以不用考虑了 50 if((sum[j] - sum[i-1]) % temp == 0)//满足条件,ans++; 51 ans++; 52 } 53 } 54 printf("%lld\n",ans); 55 } 56 return 0; 57 }