我们来安利一个黑科技。(其实是Claris安利来的

比如我现在有一坨询问,每次询问两个不超过n的数的gcd。

n大概1kw,询问大概300w(怎么输入就不是我的事了,大不了交互库

http://mimuw.edu.pl/~kociumaka/files/stacs2013_slides.pdf

http://drops.dagstuhl.de/opus/volltexte/2013/3938/pdf/26.pdf

我们定义一个数k的一种因式分解k=k1*k2*k3为“迷之分解”当且仅当k1、k2、k3为质数或小于等于$\sqrt{k}$ 。

我们发现线筛的时候对于一个数x,设x最小的质因子为p,x/p=g,那么x的“迷之分解”可以通过g的“迷之分解”中三个数最小的一个乘上p得到。

证明似乎可以用数学归纳法证(然而我证不出来啊

然后对于每两个小于等于$\sqrt{n}$ 的数我们可以打一张gcd表出来。

最后如果我们要询问gcd(x,y),我们找到x的“迷之分解”,然后如果分解的一部分小于等于$\sqrt{n}$ 那就查表,否则那就是一个质数,分类讨论一下就行了。

伪代码:

UPD:实际测试了一下随机数据跑得并没有沙茶gcd快。可能是我实现的姿势不够优越(雾

大家可以测试一下跑gcd(5702887,9227465)这个算法比沙茶gcd不知道快到哪里去了

//跑得比谁都快的gcd?
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <math.h>
#include <time.h>
#include <limits>
#include <set>
#include <map>
using namespace std;
const int N=;
const int sn=sqrt(N);
bool np[N+];
int ps[N+],pn=;
int cs[N+][];
void xs()
{
np[]=cs[][]=cs[][]=cs[][]=;
for(int i=;i<=N;i++)
{
if(!np[i]) {cs[i][]=cs[i][]=; cs[i][]=i; ps[++pn]=i;}
for(int j=;j<=pn&&i*ps[j]<=N;j++)
{
np[i*ps[j]]=;
int cm=cs[i][]*ps[j];
if(cm<cs[i][])
{
cs[i*ps[j]][]=cm;
cs[i*ps[j]][]=cs[i][];
cs[i*ps[j]][]=cs[i][];
}
else if(cm<cs[i][])
{
cs[i*ps[j]][]=cs[i][];
cs[i*ps[j]][]=cm;
cs[i*ps[j]][]=cs[i][];
}
else
{
cs[i*ps[j]][]=cs[i][];
cs[i*ps[j]][]=cs[i][];
cs[i*ps[j]][]=cm;
}
if(i%ps[j]);else break;
}
}
}
int gcdd[sn+][sn+];
void smgcd()
{
for(int i=;i<=sn;i++) gcdd[i][]=gcdd[][i]=i;
for(int i=;i<=sn;i++)
{
for(int j=;j<=i;j++) gcdd[i][j]=gcdd[j][i]=gcdd[i-j][j];
}
}
void pre_gcd() {xs(); smgcd();}
int gcd(int a,int b)
{
if(a>N||b>N)
{
puts("Fuck You\n");
return -;
}
int *x=cs[a],g=;
for(int i=;i<;i++)
{
int d;
if(x[i]<=sn) d=gcdd[x[i]][b%x[i]];
else if(b%x[i]) d=;
else d=x[i];
g*=d; b/=d;
}
return g;
}
int euclid_gcd(int x,int y)
{
while(y)
{
int t=x%y; x=y; y=t;
}
return x;
}
int tmd=-;
void gc()
{
if(tmd==-) tmd=clock();
else
{
printf("Passed: %dms\n",clock()-tmd);
tmd=-;
}
}
int main()
{
int seed=time();
//1kw个随机数测试
int ans;
printf("Euclid gcd...\n");
srand(seed);
gc();
ans=;
for(int i=;i<=;i++)
{
int a=(rand()*+rand())%N+,b=(rand()*+rand())%N+;
ans^=euclid_gcd(a,b);
}
printf("Ans = %d\n",ans);
gc();
printf("New gcd...\n");
srand(seed);
gc();
pre_gcd();
ans=;
for(int i=;i<=;i++)
{
int a=(rand()*+rand())%N+,b=(rand()*+rand())%N+;
ans^=gcd(a,b);
}
printf("Ans = %d\n",ans);
gc();
}

最新文章

  1. UWP 统一平台开发介绍
  2. jsp页面显示数据库乱码
  3. 解决kettle配置文件中的中文乱码
  4. eBay Notification介绍
  5. xorm使用pgsql的例子
  6. WPF学习01:初始XAML浅析
  7. Hoax or what
  8. C#总结2
  9. Android短信的发送和接收监听
  10. 10分钟学会Linux
  11. mac jmeter 的使用
  12. angular1与swiper
  13. 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
  14. 安卓----Spinner
  15. 起泡排序(Bubble sort)
  16. VS2008引入头文件包含目录和lib库目录
  17. Element Select 回显
  18. ZOJ 4070 - Function and Function - [签到题][2018 ACM-ICPC Asia Qingdao Regional Problem M]
  19. NET 架构指南频道
  20. Spring JdbcTemplate源码阅读报告

热门文章

  1. 对Xcode菜单选项的详细探索(干货)
  2. 操作系统开发系列—11.ELF格式 ●
  3. cocoaPods框架管理工具使用
  4. 干货之运用CALayer创建星级评分组件(五角星)
  5. iOS中响应者链条-触摸事件
  6. c中的关键字、标识符、注释
  7. android 进程/线程管理(一)----消息机制的框架
  8. CVEH项目观察与思考
  9. mysql动态行转列
  10. 利用iframe实现无刷新上传处理