本文介紹的常數優化方法能使代碼加速到原來的一半甚至更快

使用union類

定義

union是一種特殊的類,定義方法如下(定義在main內或main外都可以)

union Union{
	int a;
	double b;
	char c;
};
Union u;

互斥的特性

union的所有成員存儲在同一個地址上,因此在任意時刻,union中只能有一個成員有值,例如以下代碼就是錯誤的

U.a = 27;
U.b = 6.7;
cout << U.a;
return 0;

正是由於此特性,union不僅節約空間,而且使得變量更容易被存儲到高速緩存中,從而起到常數優化作用

在union中加入對象

可以在union中加入對象,例如

class Class{
	int a;
};
union Union{
	Class test;
	int n;
};

以上代碼如果要通過union修改a的值,需要將a定義為public,如下

#include<bits/stdc++.h>
using namespace std;
class Class{
public:
	int a;
};
union Union{
	Class test;
	int n;
};
Union u;
int main(){
    u.test.a = 114;
    cout << u.test.a;
    return 0;
}

以上代碼可以正常運行,如果將第4行的public改為private或protected,則不能編譯

一個循環分多路執行

以下兩段代碼

int sum = 0;
for(int i = 1; i <= n; i++){
	sum += a[i];
}

int sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0;
for(int i = 1; i <= n; i += 4){
	sum1 += a[i];
	sum2 += a[i + 1];
	sum3 += a[i + 2];
	sum4 += a[i + 3];
}

前者運行時間大約是後者的兩倍

位運算小技巧

這部分引自《論程序底層優化的一些方法和技巧》

無分支地求絕對值

int abs(int x){
	int y = (x >> 31);
	return (x + y) ^ y;
}

無分支地求最大值

int max(int x, int y){
	int m = (x - y) >> 31;
	return y & m | x & (~m);
}

不使用除法求平均數

int average(int x, int y){
	return (x & y) + ((x ^ y) >> 1);
}

不使用中間變量交換兩個數(節約空間)

void swap(int &x, int &y){
	x ^= y;
	y ^= x;
	x ^= y;
}

使原來為a的x變為b

x ^= a ^ b;

高維數組尋址非常慢

舉個例子,與其寫

if(a[i][j][k][l] > a[i][j][k - 1][l] + a[i][j][k][l - 1]){
	a[i][j][k][l] += a[i][j][k - 1][l] + a[i][j][k][l - 1];
}

不如寫成

int &p = a[i][j][k][l], tmp = a[i][j][k - 1][l] + a[i][j][k][l - 1];
if(p > tmp){
	p += tmp;
}

這樣優化的效果在dp中尤其明顯

另外,某一維很小,如

dp[10000000][2]

則應當定義為大小為10000000的結構體或兩個數組,如下

struct DP{
	int a, b;
}dp[10000000];
//or
dp0[10000000], dp1[10000000];

而在這兩種寫法中,又推薦使用結構體

高維數組儘量按內存連續訪問

不能避免使用高維數組時,應注意這一點

以下兩段代碼

int a[10000][10000], sum = 0;
for(int i = 0; i < 10000; i++){
	for(int j = 0; j < 10000; j++){
		sum += a[i][j];
	}
}

int a[10000][10000], sum = 0;
for(int i = 0; i < 10000; i++){
	for(int j = 0; j < 10000; j++){
		sum += a[j][i];
	}
}

後者運行時間大約是前者的3倍,如果數組的大小是2的整數次冪,後者運行時間會達到前者的10倍以上

避免將多維數組某一位的大小定義為2的冪

根據《論程序底層優化的一些方法和技巧》中的測試,遍歷一個2048 * 2048的數組比遍歷一個2049 * 2049的數組慢大約4倍,所以,請不要將多維數組某一維的大小定義為2的冪,儘量將多維數組的每一維大小都定義為奇數。

ps.尤其是開狀壓dp數組,記得大小+1