2298. 异或

(File IO): input:gcdxor.in output:gcdxor.out

时间限制: 1000 ms  空间限制: 262144 KB  具体限制

题目描述

SarvaTathagata是个神仙,一天他在研究数论时,书上有这么一个问题:求不超过n两两的数的gcd。
SarvaTathagata这么神仙的人当然觉得这个是sb题啦。学习之余,他还发现gcd的某一个特别好的性质:如果有两个数i,j满足gcd(i,j)=i^j(这里的^为c++中的异或)的话,那么这两个数组成的数对(i,j)就是一个nb的数对(这里认为(i,j)和(j,i)为相同的,并不需要计算2次)。
当然,SarvaTathagata并不会只满足于判断一个数对是否nb,他还想知道满足两个数都是不超过n并且nb的数对有多少个。
由于SarvaTathagata实在是太神仙了,他认为这种题实在是太简单了。于是他找到了你,看看你是否能解决这个问题。

输入

共一行一个整数n,含义如题所述。

输出

一行一个整数,表示nb的数对的个数。

样例输入

样例输入1

12

样例输入2

123456

样例输出

样例输出1

8

样例输出2

214394

数据范围限制

提示

样例1中共有八对,分别是:
{1,3},{1,5},{1,7},{1,9},{2,6},{1,11},{2,10},{4,12}。

提示有误,特此隐藏


Solution

这是一道数论题,涉及gcd,xor(^),二进制减法。

以上三者中,若你对任何一样过敏,请谨慎食用。

Way one(40分)

用个程序找规律

//gcdxor table
#include<bits/stdc++.h>
using namespace std;
int gcd(int ta,int tb)
{
if(tb==) return ta;
if(ta%!=&&tb%!=) return gcd(tb,ta%tb);
if(ta%==&&tb%!=) return gcd(ta/,tb);
if(ta%!=&&tb%==) return gcd(ta,tb/);
return *gcd(ta/,tb/);
} int ans[];
int n;
bool vis[],memory[][];//memory[i][j]
int search(int num)
{
if(vis[num]) return ans[num];
if(num==)
return ; vis[num]=;
int now=;
for(int i=;i<num;i++)
{
if(gcd(num,i)==(num xor i))
now++;
// if(gcd(i,num)==(i xor num))
// now++; }
// if(gcd(num,num)==(num xor num))
// now++;
ans[num]=ans[num-]+now;
return ans[num];
}
int main()
{
freopen("table4.txt","w",stdout);
cin>>n;
// int s=clock();
int k;
/*
for(k=0;k<=n;k++)
{
if(k==0) {cout<<0<<endl;continue;}
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
if(gcd(i,j)==(i xor j)){
memory[i][j]=true;
ans[k]++; }
// cout<<memory[i][j]<<" ";
}
// cout<<endl;
} cout<<k<<" "<<ans[k]/2<<endl;
}
*/
// /*
for(int k=;k<=n;k++)
{
if(k==) {cout<<<<endl;continue;}
cout<<k<<" "<<search(k)<<","<<endl;
}
// */
// int e=clock();
// cout<<e-s; return ;
}

可以无视我

找不到……

Code(40分)

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define IL inline
using namespace std;
short int diff[]{,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,};
int n,ans;
IL int gcd(int ta,int tb)
{
if(tb==) return ta;
if(ta%!=&&tb%!=) return gcd(tb,ta%tb);
if(ta%==&&tb%!=) return gcd(ta/,tb);
if(ta%!=&&tb%==) return gcd(ta,tb/);
return *gcd(ta/,tb/);
}
IL int search(int num)
{
if(num==) {
int t=;
for(int i=;i<=;i++) t+=diff[i];
return t;
}
int prev;
if(num>)
prev=search(num-);
int now=;
for(int i=;i<num;i++) if(gcd(num,i)==(num xor i)) now++;
if(gcd(num,num)==(num xor num)) now++;
return prev+now;
}
int main()
{
freopen("gcdxor.in","r",stdin);
freopen("gcdxor.out","w",stdout);
cin>>n;
for(int i=;i<=min(n,);i++)
ans+=diff[i];
if(n<=)
cout<<ans<<endl;
else
cout<<search(n)<<endl;
return ;
}

40分

其实,要是我愿意我可以把表全打出来,但是这个OJ有代码长度限制(5kb)。有毒……

Way two

从大神视角理解这道题:

看到gcd就去想数论嘛

求证:若gcd(a,b)=a xor b,则gcd(a,b)=a-b (a≥b)

转到完整证明

证明:

由更相减损法,可知gcd(a,b)=gcd(b,a-b)

这个的原理与辗转相除法类似,只是把求模换成了减法

若a-b=0,则gcd(a,b)=gcd(b,a-b)=a=b

否则a-b>0,此时gcd(a,b)=gcd(b,a-b)>a-b

所以,gcd(a,b)≥a-b

再分析xor运算和二进制减法

xor:对与每一位,若是相同则为0,若是不同则得1

1^1=0  1^0=1  0^1=1  0^0=0

减法:对于每一位,若是相同则得0,若是1 0则得1,若是0 1则得1并使上一位-1

1-1=0  1-0=1  0-1=-1  0-0=0

那么,如果两数a,b中出现了0->1的情况,则减法会使那一位上出现退位,异或(xor)则不会

所以,a xor b≥a-b

又因为(前面证明的)gcd(a,b)≥a-b

所以gcd(a,b)≥a-b≥a xor b

所以当gcd(a,b)=a xor b时,gcd(a,b)=a-b=a xor b

所以若gcd(a,b)=a xor b,则gcd(a,b)=a-b (a≥b)

证毕

回到此题

现在我已经证出来

若gcd(a,b)=a xor b,则gcd(a,b)=a-b (a≥b)

一看题目,就是当gcd(a,b)=a xor b时

那么我们就可以直接用结论了

设c=a-b,则b=a-c

若数对(a,b)符合条件

则c=a^b

故我只要枚举a和b即可!

Code(90分)

#pragma GCC optimize(2)//这个程序不开O2会超时(90分)
#include<bits/stdc++.h>
using namespace std;
int n,cnt[],sum[];
int main()
{
// freopen("gcdxor.in","r",stdin);
// freopen("gcdxor.out","w",stdout);
cin>>n;
memset(cnt, , sizeof(cnt));
for(int c = ; c <= n; c++)
for(int a = c*; a <= n; a += c) //因为a>=b,所以需要从2*c开始枚举
{
int b = a - c;
if(c == (a ^ b)) cnt[a]++;//统计每个a对应的b的数量
}//^的优先级低于==,所以要打上括号
sum[] = ;
for(int i = ; i <= n; i++)
sum[i] = sum[i-] + cnt[i];
cout<<sum[n];
return ;
}

Code(100分)

#include<bits/stdc++.h>
using namespace std;
int n,sum;
int main()
{
// freopen("gcdxor.in","r",stdin);
// freopen("gcdxor.out","w",stdout);
scanf("%d",&n);
// int s=clock();
for(int c=;c<=n;c++)//c=a-b
for(int a=c*;a<=n;a+=c) //因为a>=b,所以需要从2*c开始枚举
if(c==(a ^ (a-c))) sum++;
//统计每个a对应的b的数量
//^的优先级低于==,所以要打上括号
printf("%d",sum);
// int e=clock();
// cout<<endl<<e-s;
return ;
}

TLE?

细心的你应该发现这个:

不要怕TLE啦

如果你会算复杂度,会一点微积分,会一点金融学,你就要知道:

所以整个程序的时间复杂度为O(nlog(n))

Attention

一、^的优先级低于==,所以要打上括号

二、因为a>=b,所以需要从2*c开始枚举,使得a的最小值为2*c,b=a-c,b的初值值为c且越来越小

三、用前缀和的思想,递归sum[i] = sum[i-1] + cnt[i],即n的答案是在n-1的基础上加上这次枚举的答案

END

纪中9日T4 2298. 异或的更多相关文章

  1. 纪中21日T3 2118. 【2016-12-30普及组模拟】最大公约数

    纪中21日T3 2118. 最大公约数 (File IO): input:gcd.in output:gcd.out 时间限制: 1000 ms  空间限制: 262144 KB  具体限制 Goto ...

  2. 纪中17日T1 2321. 方程

    纪中17日T1 2321. 方程 (File IO): input:cti.in output:cti.out 时间限制: 1000 ms  空间限制: 262144 KB  具体限制   Goto ...

  3. 纪中10日T1 2313. 动态仙人掌

    纪中10日 2313. 动态仙人掌 (File IO): input:dinosaur.in output:dinosaur.out 时间限制: 1500 ms  空间限制: 524288 KB  具 ...

  4. 洛谷P1880 [NOI1995]石子合并 纪中21日c组T4 2119. 【2016-12-30普及组模拟】环状石子归并

    洛谷P1880 石子合并 纪中2119. 环状石子归并 洛谷传送门 题目描述1 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石 ...

  5. 纪中23日c组T2 2159. 【2017.7.11普及】max 洛谷P1249 最大乘积

    纪中2159. max 洛谷P1249 最大乘积 说明:这两题基本完全相同,故放在一起写题解 纪中2159. max (File IO): input:max.in output:max.out 时间 ...

  6. 纪中23日c组T3 2161. 【2017.7.11普及】围攻 斐波那契数列

    2161. 围攻 (File IO): input:siege.in output:siege.out 时间限制: 1000 ms  空间限制: 262144 KB  具体限制   Goto Prob ...

  7. 纪中18日c组模拟赛

    T2 GMOJ2127. 电子表格 (File IO): input:excel.in output:excel.out 时间限制: 1000 ms  空间限制: 262144 KB  具体限制   ...

  8. 纪中21日c组T1 1575. 二叉树

    1575. 二叉树 (File IO): input:tree.in output:tree.out 时间限制: 1000 ms  空间限制: 262144 KB  具体限制   Goto Probl ...

  9. 纪中21日c组模拟赛

    AWSL  AWSL  AWSL  AWSL AWSL  AWSL  AWSL  AWSL AWSL  AWSL  AWSL  AWSL AWSL  AWSL  AWSL  AWSL 题解传送 T1  ...

随机推荐

  1. 使用.NET Core优雅获取并展示最新疫情数据

    前言 新型冠状病毒的出现,着实让人紧张.我每天一大早都会去查看今天的最新数据,可是每次的数据都挺让人揪心的.今天突然间很想看看过去的历史的数据,结果查了很多资料都不是很全.反正国家让我们待在家里做贡献 ...

  2. 今天你上班了吗?来聊聊一个隐蔽了 5 年的BUG!

    前言 今天,我们要揭晓一个 FineUI 隐藏最深的一个BUG,这个问题从 2014-07-30 发布 FineUIPro v1.0.0 就一直存在,直到最新于 2020-01-10 发布的 v6.1 ...

  3. 利用AppMetrics对Web进行监控教程

    利用AppMetrics对Web进行监控教程 一.基础准备 1. 安装依赖 这里可以通过nuget或使用命令行进行安装,具体需要安装的类库如下(注意版本): Install-Package App.M ...

  4. angular之模块开发一

    模块化开发 概述 什么是模块化开发 将软件产品看作为一系列功能模块的组合 通过特定的方式实现软件所需模块的划分.管理.加载 为什么使用模块化开发 https://github.com/seajs/se ...

  5. python day01练习和作业

    习题:1.简述编译型与解释型语言的区别,且分别列出你知道的哪些语言属于编译型,哪些属于解释型编译型语言:优点:执行速度快 缺点:维护成本高,跨平台性差解释型语言:优点:维护成本低,跨平台性好 缺点:执 ...

  6. HTTP&&Fiddler教程

    很不错的学习资料! HTTP http://www.cnblogs.com/TankXiao/category/415412.html http://www.cnblogs.com/TankXiao/ ...

  7. 每日一练_PAT_B_真题

    A+B和C (15) 时间限制 1000 ms 内存限制 32768 KB 代码长度限制 100 KB 判断程序 Standard (来自 小小) 题目描述 给定区间[-2的31次方, 2的31次方] ...

  8. PySpark Rdd Cheat Sheet Python

  9. Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树)

    Codeforces Round #620 F2. Animal Observation (hard version) (dp + 线段树) 题目链接 题意 给定一个nm的矩阵,每行取2k的矩阵,求总 ...

  10. nmcli几个常用命令

    1.nmcli connection 用于查看连接 2.nmcli device用于查看当前网络设备 3.nmcli connection modify用于修改当前连接配置 4.nmcli conne ...