Educational Codeforces Round 24 E. Card Game Again(线段树+二分)

题目链接
在这里插入图片描述
题意:给定n个数,问有多少区间【l,r】满足区间内数的乘积是k的倍数。
思路:写了半天的二分居然超时了。。。
还是用了线段树,为了防止爆ll可以乘积%k,然后对于每一个位置进行二分,如果【li,ri】是k的倍数的话,不用说【li,ri+1】,【li,ri+2】。。。肯定也是满足的,二分查找第一个满足条件的右端点就行。

#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
typedef long long ll;
struct node{
	int l,r;
	ll sum;
}tree[maxn<<2];
ll ans=0,k,a[maxn];
void pushup(int x)
{
	tree[x].sum=(tree[x<<1].sum%k)*(tree[x<<1|1].sum%k)%k;
}
void build(int x,int l,int r)
{
	tree[x].l=l;tree[x].r=r;
	if(l==r) {
		tree[x].sum=a[l];return ;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	pushup(x);
}
ll query(int x,int l,int r)
{
	if(l<=tree[x].l&&tree[x].r<=r) return (tree[x].sum)%k;
	int mid=(tree[x].l+tree[x].r)>>1;
	ll ans=1;
	if(l<=mid) ans=(ans*query(x<<1,l,r))%k;
	if(mid<r) ans=(ans*query(x<<1|1,l,r))%k;
	return ans%k;
}
int main()
{
	int n;
	scanf("%d %lld",&n,&k);
	for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
	build(1,1,n);
	for(int i=1;i<=n;++i)
	{
		int l=i,r=n,mid;
		while(l<=r)
		{
			mid=(l+r)>>1;
			if(query(1,i,mid)%k==0) r=mid-1;
			else l=mid+1;
		}
		if(query(1,i,l)%k==0) ans+=n-l+1;
	}
	printf("%lld\n",ans);
}
发布了283 篇原创文章 · 获赞 0 · 访问量 7287

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/105127734