UVA - 12716 - 异或序列

求满足GCD(a,b) = a XOR b; 其中1<=b <=a<=n。

首先做这道题需要知道几个定理:

异或:a XOR b = c 那么 a XOR c = b;

那么我们令GCD(a,b)= c; 这样 a 是  c  倍数。我们可以通过遍历c , 然后通过筛法,把c的倍数晒出当作a。求b如何求呢?

书上提供一种方法是利用a XOR c=b 用 gcd(a,b)=c 验证。但是这个方法是超时的,gcd是logn 级别的 总的时间复杂度,n*(logn)^2。这是我们不能接受的。

还有一种方法是证明b=a-c。这个证明还是不容易的 :

首先gcd(a,b)=c<=a-b 其次要证明a^b>=a-b  但是这是不容易。我们可以这样想,他们什么时候取等于,我们知道异或是相同为0,不同为1 那么 我们把a,b用二进制展开,这样我们a,b是每一位对应的,我们把所以不同的二进制位,全部变为ai = 1,bi = 0。这样我们知道,没有借位 那么a^b == a-b 。那么后面按照XOR序列的顺序变化,a-b变小,那么a^b>=a-b 从而 c=a-b。命题得证。

证明是否成立,直接用a^b==a-b即可。可以的把,保持在f数组里面,f[i]代表a=i时的情况数。最后求一个前缀和既可以,最后o1查找即可。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
const int maxx=30000001;
int f[maxx];
void init(){
    for (int i=1;i<=maxx/2;i++){
        for (int j=2*i;j<=maxx;j+=i){
           int b=j-i;
           if ((j^b)==i){
            f[j]++;
           }
        }
    }
    for (int i=2;i<=maxx;i++){
        f[i]+=f[i-1];
    }
}
int main(){
  int t;
  int n;
  int zz=0;
  scanf("%d",&t);
  int cnt=0;
  int a;
  memset(f,0,sizeof(f));
  init();
  while(t--){
    zz++;
    scanf("%d",&n);
    printf("Case %d: %d\n",zz,f[n]);
  }
  return 0;
}

原文地址:https://www.cnblogs.com/bluefly-hrbust/p/9823465.html

时间: 2024-10-08 05:11:36

UVA - 12716 - 异或序列的相关文章

「luogu4462」[CQOI2018]异或序列

「luogu4462」[CQOI2018]异或序列 一句话题意 输入 \(n\) 个数,给定\(k\),共 \(m\) 组询问,输出第 \(i\) 组询问 \(l_i\) \(r_i\) 中有多少个连续子序列的异或和等于 \(k\).数据范围均在 \([0,1e5]\). 本题不强制在线,故莫队. 记序列 \(a\) 的前缀异或和 \(pre\),用一个桶 \(t_i\) 记录当前查询区间内前缀异或和为 \(i\) 的数量. 代码如下: #include <cstdio> #include &

UVA 12716 GCD XOR (异或)

题意:求出[1,n]中满足gcd(a,b)=a xor b,且1<=a<=b<=n的对数 题解:首先a xor b = c,则a xor c = b,而b是a的约数,则可以使用素数筛选法的方法使用O(nlogn)枚举a与c      接着gcd需要O(logn)的时间,时间为O(n(logn)^2) 但是我们还可以继续优化掉一个log,我们打表找规律可以看出c=a-b 证明:因为a - b(相同为0,不同为1或者-1) <=a xor b(相同为0,不同为1),又因为gcd(a,b

UVA 12716 GCD XOR【异或】

参考:http://www.cnblogs.com/naturepengchen/articles/3952145.html #include<stdio.h> #include<string.h> #include<time.h> const int N=3e7+11; int ans[N]; int gcd(int a,int b){ if(!b) return a; return gcd(b,a%b); } void init(){ for(int c=1;c&l

异或序列 [set优化DP]

也许更好的阅读体验 \(\mathcal{Description}\) 有一个长度为 \(n\)的自然数序列 \(a\),要求将这个序列分成至少 \(m\) 个连续子段 每个子段的价值为该子段的所有数的按位异或 要使所有子段的价值按位与的结果最大,输出这个最大值 \(T\)组询问 \(T\leq 10,n,m\leq 1000,a_i\leq 2^{30}\) \(\mathcal{Solution}\) 实际上数据范围可开大很多 我们贪心的一位一位的确定最终答案,即看当前考虑的位能否为\(1\

UVa 12716 &amp;&amp; UVaLive 6657 GCD XOR (数论)

题意:给定一个 n ,让你求有多少对整数 (a, b) 1 <= b <= a 且 gcd(a, b) = a ^ b. 析:设 c = a ^ b 那么 c 就是 a 的约数,那么根据异或的性质 b = a ^ c,那么我们就可以枚举 a 和 c和素数筛选一样,加上gcd, n*logn*logn. 多写几个你会发现 c = a - b,证明如下: 首先 a - b <= a ^ b,且 a - b >= c,下面等于等号,用反证法,假设存在 a - b > c,那么 c

P4462 [CQOI2018]异或序列

题目描述 已知一个长度为n的整数数列 a1,a2,...,ana_1,a_2,...,a_na1?,a2?,...,an? ,给定查询参数l.r,问在 al,al+1,...,ara_l,a_{l+1},...,a_ral?,al+1?,...,ar? 区间内,有多少子序列满足异或和等于k.也就是说,对于所有的x,y (I ≤ x ≤ y ≤ r),能够满足 ax?ax+1?...?ay=ka_x \bigoplus a_{x+1} \bigoplus ... \bigoplus a_y = k

Luogu P4462 [CQOI2018]异或序列

一道稍微要点脑子的莫队题,原来省选也会搬CF原题 首先利用\(xor\)的性质,我们可以搞一个异或前缀和的东西 每一次插入一个数,考虑它和之前已经加入的数能产生多少贡献 记一下之前的异或总值,然后还是利用异或的性质再异或一遍 这个我们再开一个数据统计一下出现次数. 但是唯一要注意的就是一些细节问题,尤其是左端点加入(or删除)的时候要减一 然后就可以水过了(我的代码莫队的时候写的有点骚) CODE #include<cstdio> #include<cctype> #include

[CQOI2018] 异或序列

题目链接:戳我 哈哈哈我竟然秒切了省选题 莫队+异或. 考虑异或的性质,一个数同时异或两次等于没有进行操作.那么我们设a[i]为前i个数的异或和,显然对于一个区间\([l,now]\),\(a[l-1]\oplus a[now]\)就是这个区间里面所有的数的异或和.如果\(a[l-1]\oplus a[now]=k\)那么ans++,这等同于\(a[l-1]=k\oplus a[now]\). 代码如下: #include<iostream> #include<cstdio> #i

P4462 [CQOI2018]异或序列 莫队 异或

题目描述 已知一个长度为n的整数数列a_1,a_2,...,a_na1?,a2?,...,an?,给定查询参数l.r,问在a_l,a_{l+1},...,a_ral?,al+1?,...,ar?区间内,有多少子串满足异或和等于k.也就是说,对于所有的x,y (I ≤ x ≤ y ≤ r),能够满足a_x \bigoplus a_{x+1} \bigoplus ... \bigoplus a_y = kax??ax+1??...?ay?=k的x,y有多少组. 输入格式 输入文件第一行,为3个整数n