今天讲一讲数论吧(虽然清明讲过了)

进制转换

我们来看10这个数怎么转换成k进制

因为10=2^3+2^1,所以10就是1010

三进制也同理10=3^2+3^0,所以就是101

我们对于一个10进制数,就可以用短除法来求解

比如55的三进制

这里我们把所有的余数向上写一遍,其实代码实现的话就直接写一个栈就可以了,还有一个没啥用的注意事项,就是读的问题

怎么把一个k进制数转成十进制的X?

假设我们有一个k进制数X,总共有n位,那么他就是XnXn-1Xn-2......X1X0

我们第i位其实就对应着k^i,我们最后计算就行了

有几种特殊的进制写法,

2进制,我要写二进制1001,那我就写int a=01001(因为正常的数不会前导0)

8进制,

10进制,

16进制,我要写1001,就是0x1001,算一下就是16^3+1=4097

注意,

16进制是0-15,大于9的数字我们用字母代替,所以就是0123456789ABCDEF

高精度

因为我们知道即使是long long也是-2^63~2^63,差不多也就是二十位左右,但是我们有那种好几百位的,就很变态了

所以我们考虑用到高精度

其实就是模拟竖式进行加减法

比如2333+233=2566

肯定就是

第一个问题,我们怎么把这个数存下来(当然是用字符数组读入然后转成)

正常想法是正着存进去啊

但是肯定是有问题的

我们存了19260817,但是后来又加了一个123,所以我们高精度存数就是反着存的

也就是存的是71806291我们计算的时候就可以从下标0开始计算了

这样就能保证做加法的时候各位一定是对齐的

因为之前我们学习的这里我们学一个新的高精度写法,

把相关运算符进行重载,也就是说对高精度本身进行构造(其实就相当于手写python的底层高精实现)

就是说因为很多题是不光只有高精度的,所以我们在调试的时候就先开int,当我们过掉小数据就证明我们的思路没有问题,那我们直接把int改成高精类型,把之前的模板贴进去就行了

这里还有一个代码的写法问题,我们之前是面向过程的编程语言,那么现在学一下面向对象的编程语言,这一点在北大的那本算法程序设计有讲到,主要的就是模块化,可修改化的问题

所以我们开一个struct

struct gaojing
{
int z[];//用来存这个数的数组
int l;//这个高精度是个l位的数
};

里面有两个值z[]和l分别表示数字本身和长度

但是我们这里有一个坑,struct里面的值是很玄学的,有可能是随机值也有可能全是0

即使我保证初始全是0,他也是错了,为什么?

比如我a=0,那么a.z[xxxx]==0没问题,但是其本身长度是1啊,所以我们得把l改成1

但是我们肯定不能每一个数都给它memest一遍,这样太慢了,所以我们得用一下构造函数

就是说我们每一次构造一个gaojing类型的数的时候,就自动改变他的值,这样就方便很多了

高精度的板子一定要手写,因为它的本质其实就是一个大模拟,而且说句实话数据结构什么的也都是模拟,我们一定要熟练运用

我们最好是把这几个运算符都给它编写一下

C++里面有一种特殊的函数叫做重载运算符,是这样写的

数据类型   operator  (你要重载的符号)(你要算的数)

gaojing operator+(gaojing a,gaojing b)
{
XXXXXXX
retrun ans;
}

重载运算符对于普通运算是没有问题的,两个数都是gaojing类型的时候,他才会走这个函数,并且返回一个a+b的gaojing类型的值

但是这是有问题的,为什么?(ZHX最喜欢干这种恶心的事情了)

我们看一看另一个代码

gaojing operator + (gaojing &a,gaojing &b)
{
bulabulabula
return ans;
}

括号当中因为加了一个&,所以我们会对于外面的数产生影响

原因是这样的

F()在实现的时候,是先把a拷贝一份a’然后传给F(),所以我们怎么改都不会对原型有影响,但是我们在G()实现的时候,直接把a传了过去,而没有备份

再回头看这个代码,我们做这个高精加法运算的时候,如果不加&,所以每一次都要拷贝二十多万位的数组,那这就很刺激啊。。。。。

肯定很多人会认为就已经对了

但是还是错的。。。。。。。因为我们很有可能算出来的答案是对的,但是很有可能把a和b的值改了,这个事情就很玄学啊对吧,所以我们就得在类型前加一个const,来使a不会改变

而且如果想要用STL也就是sort这些对gaojing进行操作的话,你不加&是不行的

我们来看代码吧

我们看到21行,这里取了两个gaojing数位较长的那个,这个自己想一想也能明白

然后就是正常进行加法,之后取模运算就可以,但是最后有一个很刺激的情况啊,就是说有可能我们两个数相加之和位数会变多一位,所以我们看28行,对最后的实际位数进行运算,这样出来的位数就是正确的了、

我们还得重载一下输入输出

Friend代表有源函数,i代表input,stream代表流,所以istream就是读入流

Static代表静态变量,而且去掉是错的,我们一定要记住,在函数里面一定不要开数组,如果非要开,那也得是加seatic,不然会爆系统栈

然后正常读入就好,最后我们要记住返回cin

同样的还有Cout,和cin类似吧,但是有一点是要加一个const,这是为了保证我们输出的时候a的值不会变,同样的,最后我们要返回一个cout

再看乘法的代码

取第一个数的第i位和第二个数的第j位相乘,把答案加到c的第i+j位上,因为一个a位数乘以一个b位数最多是有a+b位,也就是c.l=a.l+b.l

这里就是进位过程

但是因为不一定所有的数乘出来最后都会把位数补满,所以我们要检测他到底有多少位

终于开始讲数论了

指数定义:

以π(x)表示不超过x的素数的个数,我们可以证明

Lim(x->∞)π(x) ln x/x=1

先是判断素数

for(int i=;i<=sqrt(n); ++i)
if(n%i==) return false;
return true;

但是有一个问题,这个代码会把所有小于等于1

的数会判为质数,所以我们加一个判断式

再写一下优化就是了

时间复杂度是sqrt(n)(没优化是O(n))

然后就是求区间的筛法

用刚才那个方法能够得到一个O(n*sqrt(n))的方法,但是太慢了

我们得换个方法,就是说我们把所有的质数的倍数都标记为不是质数,最后剩下的就都是质数了,所以我们转换成代码的话就是这样的

for (int i=,i<=n;++i)
for(int j=i+i;j<=n;j+=i)
prime [j] =false;

这玩意的时间复杂度就是O(nlogn)

这里的logn是怎么来的呢?其实就是   n/2+n/3+n/4+....+n/n
≈n(1+1/2+1/3+...+1/n)
≈n log n

上面那个式子叫做调和级数

有一个非常经典的民科《调和级数既是收敛的又是发散的》(可以当笑话看)

怎么做优化?
实际上,我们只需要让一个数只被质数筛掉就行

这就是埃拉托色尼筛法

for(a=;a<=n;a++)
if(not_prime[a]=false)
for(int b=+;b<=n;b+=a)
not_prime[b]=true;

这样的话我们就做到了只把指数的倍数筛掉的,埃拉托色尼筛法的复杂度是O(Nloglogn)

最后讲一种线性的筛法

我们希望每个数只被筛掉一次,来看代码吧

memset(not_prime,,sizeof(not_prime));//初始化为都是质数
not_prime[]=true;//1不是质数
for(int i=;i<=n;i++)
{
if(!not_prime[i]) prime[++prime_count]=i;
//如果i还没有被标记为不是质数 ,就把i加到质数表里面
for(int j=;j<=prime_count;j++)
{
if(prime[j]*i>n) break;//枚举i的质数倍
not_prime[prime[j]*i]=true;
if(i%prime[j]==) break;
//如果i是第j个质数的倍数,就跳出循环
//因为i有prime[j]这个因子,再枚举prime[j]就会变大
//break掉就可以保证一定是被它的最小质因子筛掉
}
}

我们一开始认为所有的数都是质数,除了1

第三行是如果i是质数,那么把i假如质数表中

第4行开始枚举当前质数表里所有的质数

我们原来的方法是枚举i的任意倍数,但是这里就成了枚举i的质数倍

其实这里看懂很容易,我们只需要加上一个输出调试,你就能看出来他是怎么筛的了

GCD(最大公因数)

这玩意很好写,用辗转相除法就行

int gcd(int a,int b)
{
if(b==) return a;//gcd(a,0)=a
else return gcd(b,a%b);
}

STL里头有一个自带的函数__gcd(x,y)但是貌似CCF是不让用的

有了GCD我们就能解同余方程

gcd(a,b)=g
==>ax+by=g(x,y∈Z)

如:
gcd(30,12)=6
==>1*30-2*12=6
==>-1*30+3*12=6
显然结果有无数组

已经知道gcd(a,b)=g
求一组ax+by=g解

拓展欧几里得算法:

int exgcd(int a,int b,int &x,int &y)
{
if(b==)//到了最底层
{
x=,y=;//这是一组解
return a;//最大公因数
}
else
{
int g=exgcd(b,a%b,x,y);
int t=x;
x=y,y=t-a/b*x;//x'=y,y'=x-y*(a/b)
return g;
}
}

还有一个问题就是求逆元,这个是在模一个数意义下来代替除法的,详情还是看数学班的笔记吧

QBXT Day 4 数学,数论的更多相关文章

  1. 具体数学数论章-----致敬Kunth

    整除性(divisible): 引入了代表整除性. m\n (m|n) 表示m整除n.注意这里的整除.表示的是n = km(k为整数). 在整除性这里.m必须是个正数.也许你可以描述n 是 m 的k倍 ...

  2. NOIP复习之1 数学数论

    noip一轮复习真的要开始啦!!! 大概顺序是这样的 1.数学 2.搜索贪心 3.数据结构 4.图论 5.dp 6.其他 数学 1.数论 数论被称为数学皇冠上的明珠,他的重要性主要在于它是其他学习的祖 ...

  3. 数学--数论--HDU - 6395 Let us define a sequence as below 分段矩阵快速幂

    Your job is simple, for each task, you should output Fn module 109+7. Input The first line has only ...

  4. 数学--数论--HDU 2582 F(N) 暴力打表找规律

    This time I need you to calculate the f(n) . (3<=n<=1000000) f(n)= Gcd(3)+Gcd(4)+-+Gcd(i)+-+Gc ...

  5. Codeforces 622F 「数学数论」「数学规律」

    题意: 给定n和k,求 1 ≤ n ≤ 109, 0 ≤ k ≤ 106 思路: 题目中给的提示是对于给定的k我们可以求出一个最高次为k+1的关于n的通项公式. 根据拉格郎日插值法,我们可以通过k+2 ...

  6. 算法模板の数学&数论

    1.求逆元 int inv(int a) { ) ; return (MOD - MOD / a) * inv(MOD % a); } 2.线性筛法 bool isPrime[MAXN]; int l ...

  7. 模板 - 数学 - 数论 - 扩展Euler定理

    费马(Fermat)小定理 当 \(p\) 为质数,则 \(a^{p-1}\equiv 1 \mod p\) 反之,费马小定理的逆定理不成立,这样的数叫做伪质数,最小的伪质数是341. 欧拉(Eule ...

  8. 模板 - 数学 - 数论 - Miller-Rabin算法

    使用Fermat小定理(Fermat's little theorem)的原理进行测试,不满足 \(2^{n-1}\;\mod\;n\;=\;1\) 的n一定不是质数:如果满足的话则多半是质数,满足上 ...

  9. 模板 - 数学 - 数论 - Min_25筛

    终于知道发明者的正确的名字了,是Min_25,这个筛法速度为亚线性的\(O(\frac{n^{\frac{3}{4}}}{\log x})\),用于求解具有下面性质的积性函数的前缀和: 在 \(p\) ...

随机推荐

  1. Python3.6全栈开发实例[001]

    检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者. li = [11,22,33,44,55,66,77,88,99,000,111,222] def func1(l ...

  2. CSDN论坛停站维护公告

    各位亲爱的用户:         CSDN论坛将于2014年11月9日23点至11月10日8点进行积分系统的升级,升级期间会影响大家的正常訪问和操作.给大家带来不便,敬请广大用户谅解.         ...

  3. opencv3计算机视觉+Python(一)

    基本I/O脚本 读/写图像文件 OpenCV的imread函数和imwrite函数能支持各种静态图像文件格式.不同系统支持的文件格式不一样,但都支持BMP格式,通常还应该支持PNG.JPEG和TIFF ...

  4. 关于付款条件ZTERM 的函数

    函数:PR_WF_PAYMENT_BLOCK_CHECKCALL FUNCTION 'FI_F4_ZTERM' F061 支付的过程条件FI_CHANGE_PAYMENT_CONDITIONS New ...

  5. BAPI_ACC_DOCUMENT_POST 解决原因代码输入问题-利用BADI

    (1)    复制函数SAMPLE_INTERFACE_RWBAPI01为Z SAMPLE_INTERFACE_RWBAPI01 *"---------------------------- ...

  6. 软件磁盘阵列(RAID)

    RAID软件磁盘阵列 RAID 即廉价磁盘冗余阵列,其高可用性和可靠性适用于大规模环境中,相比正常使用,数据更需要被保护.RAID 是将多个磁盘整合的大磁盘,不仅具有存储功能,同时还有数据保护功能. ...

  7. QuickSort again

    I wrote a blog about Quick Sort before. Let's talk more about it. If you don't think that the implem ...

  8. Putty常用属性设置

    1. 使用 UTF-8避免显示乱码 2.调整 Lines of scrollback,能够回看更多的控制台输出log 3.调整颜色和字体使得看上去更舒服 4.解决数字键盘无法输入数字的问题 效果图:

  9. 分布式计算开源框架Hadoop入门实践(二)

    其实参看Hadoop官方文档已经能够很容易配置分布式框架运行环境了,不过这里既然写了就再多写一点,同时有一些细节需要注意的也说明一下,其实也就是这些细节会让人摸索半天.Hadoop可以单机跑,也可以配 ...

  10. PHP 实现Session入库/存入redis

    对于大访问量的站点使用默认的Session 并不合适,我们可以将其存入数据库.或者使用Redis KEY-VALUE数据存储方案 首先新建一个session表 CREATE TABLE `sessio ...