Problem Author: | De3b0o |
Prepared by: | De3b0o |
Edited by: | Hasan Saleh (MathModel) |
Write the prime factorization of as
The of a subarray is divisible by if and only if, for every prime power p_i^{e_i}, there exists at least one element inside the subarray divisible by p_i^{e_i}. Therefore, instead of dealing with s directly, it is sufficient to ensure that each required prime power appears at least once inside the subarray.
We factorize using trial division and store all values p_i^{e_i} in an array . The number of such values is small (at most ). If k=1, then every subarray is valid and the answer is simply
For the general case, we scan the array from left to right. For every stored prime power , we maintain the last index where an element divisible by appeared, denoted by . Initially, all values of are zero. When processing position , for every such that a_i is divisible by , we update \text{last}[j]=i. Let
All subarrays ending at and starting at any position 1 \le l \le \text{id} contain all required prime powers and are therefore valid, so we add to the answer.
This is correct because for a fixed right endpoint , the smallest possible left endpoint that still contains all required prime powers is exactly \min_j \text{last}[j]. Any earlier start only adds extra elements and preserves validity. Each valid subarray is counted exactly once, at its right endpoint.
The overall complexity is O(n \cdot |P| + t \cdot \pi(\sqrt{k})). where |P| \le 13 , is the count of primes upto inclusive , \max(k)=10^{14} , \pi(10^7)=664579 thus complexity in numerical terms is : O(13 \times 2 \times 10^6+6.6 \times 10^7) which is roughly O(9 \times 10^7) at worst case.
Implementation
#include <bits/stdc++.h>
#define ll long long
#define F first
#define S second
#define in insert
#define pb push_back
#define d3 ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define cans cout << ans << "\n";
#define yes cout << "YES" << "\n";
#define no cout << "NO" << "\n";
#define pll pair<ll, ll>
#define lin cout << "\n";
#define mid ((l + r) / 2)
#define lc (2 * x)
#define rc (2 * x + 1)
#define double long double
using namespace std;
mt19937 rnd(time(0));
const int N = 2e6+9;
ll n,k,a[N];
bool s[5*N];
vector<int> v;
vector<ll> p;
int lst[20];
ll fp(ll x , ll y)
{
if(y==0)
return 1;
ll z = fp(x,y/2);
z*=z;
if(y%2)
z*=x;
return z;
}
int main()
{
d3
for(int i = 2 ; 10000>i ; i++)
{
if(s[i])
continue;
for(int j = i*i ; 5*N>j ; j+=i)
s[j]=1;
}
for(int i = 2 ; 5*N>i ; i++)
{
if(!s[i])
v.pb(i);
}
int T = 1;
cin >> T;
while(T--)
{
p.clear();
cin >> n >> k;
for(int i = 1 ; n>=i ; i++)
cin >> a[i];
if(k==1)
{
cout << n*(n+1)/2 << "\n";
continue;
}
for(auto it : v)
{
if(k==1)
break;
if(k%it)
continue;
ll e = 0;
while(k%it==0)
{
k/=it;
e++;
}
p.pb(fp(it,e));
}
if(k>1)
p.pb(k);
ll ans = 0;
for(int8_t i = 0 ; 20>i ; i++)
lst[i]=0;
for(int i = 1 ; n>=i ; i++)
{
for(int8_t j = 0 ; p.size()>j ; j++)
{
if(a[i]%p[j]==0)
lst[j]=i;
}
int mn = i;
for(int8_t j = 0 ; p.size()>j ; j++)
mn=min(mn,lst[j]);
ans+=mn;
}
cans
}
}