洛谷普及场(分治算法)

  • 快速幂取余数(模板)
    运算符:
    & :通常用于二进制取位,x&1判断x的末尾是否为1,若x为奇数则返回1,否则返回0。
    ‘>>: 右移操作,相当于乘于2,相对的<< 左移操作为除于2(比直接乘于2和除于2要快)
    快速幂(a^b);
    当b为偶数时:a ^ b = a ^ (b/2) +*a^(b/2) ; (例如:2^6 = 2^3 * 2^3 )
    当b为奇数时:a ^ b = a * a^(b/2) ; (例如 : 2 ^ 5 = 2 * 2 ^ 4)
    快速幂取模:
    因为某个因子取余后相乘再取余余数保持不变,所以有以下公式
    (a ^ b)modc = (a mod c) ^ b mod c(但是在c太大的情况下可能会超时,所以又有了以下的公式)
    在这里插入图片描述
#include 
int main(){
	long long a , b , c ; 
	scanf ("%lld%lld%lld",&a,&b,&c) ;
	long long ans = 1 ; 
	printf("%lld^%lld mod %lld=",a,b,c);
	a %= c ; 
	while(b){
		if (b & 1 == 1)	//若b为奇数
			ans = (ans*a) %c ; 
		b = b >> 1 ; //右移,相当于除于2
		a = (a*a) % c ; 
	}
	ans %= c ; 
	printf ("%lld\n",ans) ;
	return 0 ;  
} 
  • p1010 幂次方(解见注释)
#include 
#include 
void f(int x){
	for (int i = 14 ; i >= 0 ; i --){
		if (pow(2,i) <= x){	//找出最大的pow(2,i) <= x 
			if (i == 0)	printf ("2(0)") ;	//不用再分解了,直接打印出来 	
			else if (i == 1)	printf ("2") ;	//为2(1)直接输出2 
			else{
				printf ("2(") ;
				f(i) ; //继续递归指数 
				printf (")") ;  
			}
			x  -= pow(2,i) ; 
			if(x != 0)	printf ("+") ; 
		}
	}
}
int main(){
	int n ; 
	scanf ("%d",&n) ;
	f(n) ; 
	return 0 ;  
} 

  • p1908 逆序对(归并排序)

一个数组的归并排序,先将一个数组二分,一直分到只有一个元素然后开始合并,
洛谷普及场(分治算法)_第1张图片
图解来源:https://www.jianshu.com/p/33cffa1ce613

每次划分完左右区间后,左边的区间一定已经是顺序的了,这时候只要统计右边区间会与左边区间产生多少对逆序对即可;
例如:(左区间(i):5,6,10)(右区间(j):3,4,12)
合并时:
1、5>3 , 产生了逆序对而且排在5后面未被合并的数都比3大,即一共有三对逆序对(左区间长度 - 当前左区间元素下标 + 1);
2、5>4同样产生3对逆序对,然后一直对比合并下去。

#include 
typedef long long ll ;
const int N = 5e5 + 10 ; 
int f[N] , g[N] ;
long long ans ;
int inline read(){
	int f = 1 , x = 0 ; 
	char ch = getchar() ; 
	while(ch < '0' || ch > '9'){
		if (ch == '-')	f = -1 ; 
		ch = getchar() ; 
	}	
	while(ch >= '0' && ch <= '9'){
		x = (x<<3) + (x<<1) + (ch^48) ; 
		ch = getchar() ; 
	}
	return f*x ; 
} 
void inline print(long long x){
	char num[200] ; 
	if (x < 0){
		putchar('-') ; 
		x = -x ; 
	}
	ll len = -1 ; 
	while(x){
		num[++len] = x%10 + '0' ; 
		x /= 10 ; 
	}
	len ++ ; 
	while(len >= 0)	putchar(num[--len]) ; 
}
void merge(int l , int r){
	if (l == r)
		return ; 
	int mid = (l+r)/2 , i = l , j = mid+1 , index = l ; 
	merge(l,mid) ;
	merge(mid+1,r) ;  
	while(i <= mid && j <= r){
		if (f[i] <= f[j])	g[index++] = f[i++] ; 
		else{
			g[index++] = f[j++] ;
			ans = ans + mid - i + 1 ;
		}	  
	}
	while(i <= mid)		g[index++] = f[i++] ; 
	while(j <= r)		g[index++] = f[j++] ; 
	for (int k = l ; k <= r ; k ++)		f[k] = g[k] ; 
}
int main(){
	int n = read() ; 
	for (int i = 1 ; i <= n ; ++i)
		f[i] = read() ; 					
	merge(1,n) ; 
	print(ans) ; 
	return 0 ;  
} 

你可能感兴趣的:(洛谷普及场(分治算法))