• Luogu P3794 签到题IV


    题目大意

      给定一个长度为(n)的序列(a_1, a_2, dots , a_n)(1 leq n, a_i leq 5 imes 10^5))求有多少对$(i, j) $满足(1 leq i leq j leq n)(gcd (a_i, a_{i + 1}, dots , a_j) oplus (a_i lor a_{i + 1} lor dots lor a_j) = k)

    题解

      容易想到,当(i)不变时,随着(j)从小变大,区间(gcd)的值只会变小,且因为每次都要除以一个质因子,所以最多变小(log)次就到(1),同时区间或的值只会变大,且因为每次都会有一个二进制位变化,所以最多变大(log)次就到最大值。
      如果我们当前知道对于每个(i),所有可能出现的区间(gcd)和区间或的值,就能求出((i,j))的对数。
      同时,我们也可以由(i + 1)得到(i)可能出现的区间(gcd)和区间或的值,所以我们可以从(n)开始枚举到(1),直接求解即可。

    #include <iostream>
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    
    #define MAX_N (500000 + 5)
    #define SIZE (1 << 21)
    
    #define Getchar() (p1 == p2 && (p2 = (p1 = fr) + fread(fr, 1, SIZE, stdin), p1 == p2) ? EOF : *p1++)
    
    using namespace std;
    
    char fr[SIZE], * p1 = fr, * p2 = fr;
    
    void Read(int & res)
    {
    	res = 0;
    	char ch = Getchar();
    	while(!isdigit(ch)) ch = Getchar();
    	while(isdigit(ch)) res = res * 10 + ch - '0', ch = Getchar();
    	return; 
    }
    
    struct Interval
    {
    	int val;
    	int r;
    };
    
    int n, k;
    int a[MAX_N];
    Interval g1[25], g2[25];
    int tot1, tot2;
    long long ans;
    
    int gcd(int a, int b)
    {
    	int c;
    	while(b)
    	{
    		c = a % b;
    		a = b;
    		b = c;
    	}
    	return a;
    }
    
    void Update(int x, Interval g[], int & tot)
    {
    	g[tot + 1].val = 0x7f7f7f7f;
    	int d = 0;
    	for(int i = 1; i + d <= tot; ++i)
    	{
    		g[i] = g[i + d];
    		while(g[i + d].val == g[i + d + 1].val)
    		{
    			g[i] = g[i + d + 1];
    			++d;
    		}
    	}
    	tot -= d;
    	return;
    }
    
    int main() 
    {
    	Read(n); Read(k);
    	for(int i = 1; i <= n; ++i)
     	{
    		Read(a[i]);
    	}
    	int t1, t2;
    	g1[0].r = g2[0].r = n + 1;
    	for(int i = n; i; --i)
    	{
    		for(int j = 1; j <= tot1; ++j)
    		{
    			g1[j].val = gcd(g1[j].val, a[i]);
    		}
    		for(int j = 1; j <= tot2; ++j)
    		{
    			g2[j].val |= a[i];
    		}
    		g1[++tot1] = g2[++tot2] = (Interval){a[i], i};
    		Update(i, g1, tot1);
    		Update(i, g2, tot2);
    		t1 = tot1;
    		t2 = tot2;
    		while(t1 && t2)
    		{
    			if((g1[t1].val ^ g2[t2].val) == k) 
    			{
    				ans += min(g1[t1 - 1].r, g2[t2 - 1].r) - max(g1[t1].r, g2[t2].r);
    			}
    			if(g1[t1 - 1].r <= g2[t2 - 1].r) --t1;
    			else --t2;
    		}
    	}
    	printf("%lld", ans);
    	return 0;
    }
    
  • 相关阅读:
    TFS对签入文件忽略设置,解决pdb弹出警告
    利用MSSQL对不经常使用的表进行依赖缓存
    IIS 使用多个https和通配证书解决方案
    传递参数安全验证代码示例
    利用GetType反射方法再调用方法进行传递参数实现调用
    ms10_002 IE浏览器漏洞
    ms17-010漏洞复现
    ms08-067漏洞复现
    tomcat使用log4j管理日志
    Popen No such file or directory 错误
  • 原文地址:https://www.cnblogs.com/kcn999/p/11355193.html
Copyright © 2020-2023  润新知