时间复杂度 位运算 快速幂

大部分是转载的,感谢今天上课的学长

时间复杂度

•度量算法的运行时间

•一般题目的运行时间在1s左右,c++运行的极限时间数量级在10^8,如果常数过大也会超时,所以算法的时间复杂度应该控制在10^7以内

•时间复杂度运算规则:

加法法则(并列加),乘法法则(嵌套乘),最大阶法则(忽略低阶,常量,系数)

•常量阶:

只要代码的执行时间不随n 的增大而增长,这样代码的时间复杂度都记作 O(1)。或者说,一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)。

•对数阶:

2º·2¹·2²·2³····2ⁿⁿ =n,其中nn为项数 ,执行了nn次,nn= log₂n,时间复杂度为O( log₂n )

•线性阶:

一般情况下,如果循环体内循环控制变量为线性增长,那么包含该循环的算法的时间复杂度为O(n);

•N方阶:

线性阶嵌套的时间复杂度

•线性对数阶:

当一个线性阶代码嵌套一个对数阶代码时时间复杂度为O(nlogn)

•指数阶和阶乘阶:

一般出现在枚举暴力的算法,随着n增加运行时间急剧增加。不同数据大小对应合适的时间复杂度

log2n时间复杂度例子

while(i

空间复杂度

•空间复杂度定义:

程序指令代码的空间,常数、简单变量、定长成分(如数组元素、结构成分、对象的数据成员等)变量所占空间。这部分属于静态空间。

•在竞赛中不用太关注空间复杂度,一般确保自己开的静态数组不超限即可

位运算

•运算符号和描述:

&与,|或,^异或,~取反,>>右移,<<左移

•位运算的高级运算:
时间复杂度 位运算 快速幂_第1张图片

•1.求n的第k+1位数:n>>k&1

•2.求n的最后一位1的位置

int lowbit(int n){
return n&-n;
}

•Lowbit函数返回最后一位1对应的数字

•Lowbit函数证明过程:

•负数在计算机里以补码形式存储,所以-n即为n的按位取反后+1

•n原来后几位0先变为1,再+1以后一直进位,进到取反后第一个0出现的位置,恰好对应原来n最后一位1的位置

时间复杂度:思考比较朴素做法和lowbit

lowbit运算例子

n=152

n=0,10011000

-n=1,01100111+1=1,01101000

n&-n=1000

lowbit(n)=8

快速幂 快速求a的b次方算法
•朴素做法:

循环b次,每次乘一个a,时间复杂度O(n)

//求幂朴素做法
int mi(int a,int b){
    int res=1;
    for(int i=0;i
•优化做法:

利用位运算降低时间复杂度

快速求幂例子

求a^b:

b=1100011011

从低到高位依次对应a^1,a^2,a^4,a^8……

我们可以发现,后一位是前一位的平方,所以我们在循环内部可以每次更新a为原来的平方来实现

//快速幂模板
int qmi(int a,int b){
    int res=1;
    while(b){
        if (b&1){
            res=res*a;
            b>>=1;
        }
        a=a*a;
    }
    return res;
}
•过程:

将b看成2进制数,每一位对应a的某次方,若此为为0则不乘,若为1则乘,循环次数变为b的二进制位数,时间复杂度也因此将为O(log2n)

eg:给定n组a,b,p,对于每组数据,求出a^b mod p的值。

输入格式

第一行包含整数n

接下来n行,每行包含3个整数a,b,p

输出格式

对于每组数据,输出一个结果,表示a^b mod p的值。

每个结果占一行。

数据范围

1<=n<=100000

1<=a,b,p<=2*10^9

#include 

int qmi(int a,int b,int p){
    int res=1;
    while(b){
        if((b&1) == 1){
            res=(long long)res*a*p;//注意数据范围
        }
        b >>= 1;
        a=(long long)a*a%p;
    }
    return res; 
}
int main(){
    int n;
    scanf("%d%d%d",&a,&b,&p);
    int ans=qmi(a,b,p);
    printf("%d\n",ans);
    
}

你可能感兴趣的:(acm培训,算法,数据结构,c语言)