1. 程式人生 > >【JZOJ3518】進化序列【模擬】

【JZOJ3518】進化序列【模擬】

題目大意:

題目連結:https://jzoj.net/senior/#main/show/3518
題目圖片:
http://wx2.sinaimg.cn/mw690/0060lm7Tly1fy2vsa8tmfj30jd0boaab.jpg
http://wx2.sinaimg.cn/mw690/0060lm7Tly1fy2vsa8oz7j30j309t3yi.jpg

給出一個數列,求 a i  

o r   a i + 1  
o r . . . o r   a j
  m a_i\ or\ a_{i+1}\ or...or \ a_j\leq\ m i , j i,j 個數。


思路:

很明顯的,如果 a i   o r . . . o r   a j m a_i\ or...or\ a_j\leq m ,那麼 a i + 1   o r . . . o r   a j   m a_{i+1}\ or...or\ a_j\leq\ m
那麼就可以維護兩個指標 i , j i,j ,表示 a i   o r . . . o r   a j m a_i\ or...or\ a_j\leq m ,每次往後移一位 j j ,用 n u m [ k ] num[k] 表示從 a i a_i a j a_j 中二進位制下第 k k 位是 1 1 的個數。將 n u m num 所表示的數和 m m 比較,如果還符合要求,那麼 a n s ans 就要加 j i j-i 。因為 a i   o r . . . o r   a j m a_i\ or...or\ a_j\leq m ,那麼 a i + 1   o r . . . o r   a j   m a_{i+1}\ or...or\ a_j\leq\ m a i + 2   o r . . . o r   a j   m a_{i+2}\ or...or\ a_j\leq\ m ,以此類推。
如果不符合要求,那麼就將 i i 指標往後移。知道符合要求為止。
時間複雜度 O ( n   l o g   n ) O(n\ log_\ n)


程式碼:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;

const int LG=31;
const int N=100100;
int n,m,i,j,a[N],num[LG+1];
ll ans;

bool check()  //判斷num大還是m大
{
	int mm=0;
	for (int i=LG;i>=1;i--)
		mm+=((num[i]>0)*(1<<(i-1)));
	return mm<m;
}

void write(ll x)  //輸出流,防止炸long long
{
	if (x>9) write(x/10);
	putchar(x%10+48);
}

int main()
{
	freopen("evolve.in","r",stdin);
	freopen("evolve.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (i=1;i<=n;i++)
		scanf("%d",&a[i]);
	j=1;
	i=0;
	while (i<n)
	{
		i++;
		for (int k=1;k<=LG;k++)
			num[k]+=((a[i]&(1<<(k-1)))==(1<<(k-1)));
		while (!check())
		{
			for (int k=1;k<=LG;k++)
				num[k]-=((a[j]&(1<<(k-1)))==(1<<(k-1)));
			j++;
		}
		ans+=(ll)max((i-j),0);
	}	
	write(ans);
	return 0;
}