【CF992D】Nastya and a Game(思维好题)

子序列肯定不可能是无限长的

由于amax=1e8 nmax=2e5 kmax=1e5

则summax=1e82e51e5=2e18 而longlong刚好能hold住

那也就是说一个子序列里面非1的个数不超过64个(longlong范围是2^64)

那我们可以把连续的1缩成一坨 然后枚举每个点 暴力地往后找

具体的实现:记le[i]记录每个数左边第一个不是1的数在哪儿 然后用类似链表的方法遍历 如果乘积马上就要爆longlong了 就马上break

这样复杂度O(64*n)

#include<bits/stdc++.h>
#define N 200005
#define ll long long
using namespace std;
template<class T>
inline void read(T &x)
{
	x=0;
	static char ch=getchar();
	while(ch<'0'||ch>'9')	ch=getchar();
	while(ch>='0'&&ch<='9')	x=x*10+ch-'0',ch=getchar();
}
int n,le[N],ans;
ll k,a[N];
inline bool Overflow(ll mul,ll x)
{
	if(mul>LLONG_MAX/x)	return true;
	return false;
}
int main()
{
	read(n);	read(k);
	for(int i=1;i<=n;i++)	read(a[i]);
	for(int i=1;i<=n;i++)
	{
		if(a[i-1]!=1) le[i]=i-1;
		else le[i]=le[i-1];	//记录每个数左边第一个不是1的数在哪儿 
	}
	for(int i=1;i<=n;i++)
	{
		ll sum=a[i],mul=a[i];
		if(mul==sum*k)	ans++;
		for(int pre=i,now=le[i];;pre=now,now=le[now])
		{
			ll del=mul-sum*k;
			if(del>0&&del%k==0&&del/k<pre-now)	ans++;		//判断跳过的这段1 能否更新答案 
			if(!now||Overflow(mul,a[now]))	break;	
			mul*=a[now]; sum+=a[now]+(pre-now-1);
			if(mul==sum*k)	ans++;	
		}
	}
	cout<<ans<<endl;;
	return 0; 
}
posted @ 2018-10-24 22:06  Patrickpwq  阅读(229)  评论(0编辑  收藏  举报