E. Card Game Again
题意:给你一个序列和k,问你其有多少个子区间,满足乘积是k的倍数
n<=1e5
网上大多数是维护因子的个数,然后双指针来做,时间复杂度是
O
(
n
n
)
O(n \sqrt n)
O(nn),根号分解因子。
当还可以用线段树维护是否是k的倍数,即维护一段区间的乘积即可。若是0则指针l往后移答案加n-r+1,直到不是0为止,否则r不断后移。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+10;
ll a[maxn],tree[maxn];
int n,k;
void pushup(int x)
{
tree[x]=tree[x<<1]*tree[x<<1|1]%k;
}
void build(int l,int r,int x)
{
if(l==r) {
tree[x]=a[l]%k;
return ;
}
int mid=l+r>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
pushup(x);
}
ll query(int l,int r,int x,int st,int ed)
{
if(st<=l&&r<=ed) {
return tree[x]%k;
}
int mid=l+r>>1;
ll ans=1;
if(mid>=st) ans=query(l,mid,x<<1,st,ed);
if(mid<ed) ans=ans*query(mid+1,r,x<<1|1,st,ed)%k;
return ans;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin>>n>>k;
int l=1;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,n,1);
ll ans=0;
for(int r=1;r<=n;r++)
{
while(l<=r&&!query(1,n,1,l,r)) {
ans+=n-r+1;
l++;
}
}
cout<<ans<<endl;
return 0;
}