杂项

位运算加速技巧

  1. 乘/除以 2n,改为 << n>> n
  2. 交换两个数,swap(a, b) 改为 a ^= b, b ^= a, a ^= b
  3. 小数转整数,(int)3.14 改为 3.14 >> 0
  4. 正负号转换,x = -x 改为 x = ~x + 1
  5. x=2n 时,% x 改为 & (x - 1)
  6. 检查是否整除 2 时,i % 2 改为 i & 1
  7. 求绝对值,abs(x) 改为 (x ^ (x >> 31)) - (x >> 31)
  8. 比较两数值是否同号,a * b > 0 改为 a ^ b > 0

运算符优先级

优先级从大到小排列:

  1. 单目运算符:包括但不限于 !~++--
  2. 乘除模*/%
  3. 加减+-
  4. 左右移<<>>
  5. 比较运算符>>=<<===!=
  6. 按位运算符&^|
  7. 逻辑运算符&&||
  8. 赋值运算符:包括但不限于 =+=%=<<=&=
  9. 三目运算符?:

快读快写

int read() {
	int x = 0, f = 1;
	char ch = getchar();
	while (!isdigit(ch)) {
		ch == '-' && (f = -1);
		ch = getchar();
	}
	while (isdigit(ch)) {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x * f;
}

void write(int x) {
	if (x < 0) putchar('-'), x = ~x + 1;
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

还有重载 getchar()putchar() 的超级快读,只需加入:

char buf[1 << 20], obuf[1 << 20], *p1 = buf, *p2 = buf, *p3 = obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
#define putchar(x) ((p3-obuf<(1<<20))?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x))

快读快写函数正常写即可。程序末尾需要加一句 fwrite(obuf, p3 - obuf, 1, stdout);

火车头

#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")

对拍

#include <bits/stdc++.h>
using namespace std;

int main() {
	while (true) {
		system("data.exe > data.in");
		system("手写.exe < data.in > mine.out");
		system("标程.exe < data.in > stdd.out");
		if (system("fc mine.out stdd.out")) {
			system("pause");
			return 0;
		}
	}
}

2024/7/11 upd.

我们不管是使用 mt19937 还是 rand(),我们的随机种子使用 time(0) 的话,由于它是以秒为单位的,所以一秒之内生成的随机数据是一样的,会影响我们对拍的效率。使用以下的随机数种子可以生成毫秒级别的随机数。

struct _timeb T;
_ftime(&T);
mt19937 wdz(T.millitm);

这样的话,我们就可以做到在一秒之内运行 wdz() 依然能生成不同的随机数。

但是,该函数不能在 Linux 下运行。所以如果你在比赛的时候把它用到正式代码里面导致 CE 0pts,不要怪我。——2024/7/27 upd.


2024/7/30 upd.

遗憾地,我们不能在 Linux 环境下使用毫秒级别随机数。但这是否意味着 Linux 下不能随机化乱搞呢?当然不是的。

我们有了一个更好的随机数函数:random_device。它的用法更为简单:

random_device wdz;

此时调用 wdz() 就可以生成真随机数了。但注意,这个函数需要用到一个叫做 熵池 的高级东西,所以它在 Windows 下生成的随机数效果和不开 srand(time(0))rand() 是一样的。不过经过测试,它在 Linux 下确能生成真随机数。

位运算

快速幂模板

abmodp,其中 1a,b,p109

代码前加入 #define int long long

inline int power(int a, int b, int p) {
	int res = 1;
	while (b != 0) {
		if (b & 1) res = res * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return res % p;
}

时间复杂度 O(logb)

龟速乘模板

a×bmodp,其中 1a,b,p1018

inline int mul(int a, int b, int p) {
	int res = 0;
	while (b != 0) {
		if (b & 1) res = (res + a) % p;
		a = (a << 1) % p;
	}
	return res % p;
}

时间复杂度 O(logb)

二分

在单调递增序列 a 中查找 xx 的后继

while (l < r) {
	int mid = (l + r) >> 1;
	if (a[mid] >= x) r = mid;
	else l = mid + 1;
}
return a[l];

在单调递增序列 a 中查找 xx 的前驱

while (l < r) {
	int mid = (l + r + 1) >> 1;
	if (a[mid] <= x) l = mid;
	else r = mid - 1;
}
return a[l];

Hack

  • 卡 unordered_map:GCC 6 以前频繁插入 126271,GCC 7 以后频繁插入 107897
  • 卡 pb_ds:频繁插入 216 的倍数。

防止被卡:见 CF 大神的两篇文章。

https://codeforces.com/blog/entry/62393

https://codeforces.com/blog/entry/60737

C++ 输出变量类型

我们可以用 typeid 关键字查看变量类型,用法:

int a = 0;
cout << typeid(a).name() << '\n';

输出:

i

类似地,bool 类型输出 b,long long 类型输出 x,char 类型输出 c,string 类型输出 Ss。对于任何类型的数组,都会输出 A + 你的数组大小 + _ + 上述类型的值,例如 int a[100005] 会输出 A100005_i

然而,在输出 STL 相关类型时,typeid 会输出乱码。例如,vector<int> a 输出了 St6vectorIiSaIiEE。此时需要用以下方式将其输出解密:

#include <cxxabi.h> // 不包含在万能头中
...
auto tp = typeid(a).name(); // a 是你要输出的变量名
int tmp; // tmp 没什么用,只是函数参数需要
auto realname = abi::__cxa_demangle(tp, 0, 0, &tmp); // realname 实际上是 char * 类型
cout << realname << '\n';

此时若给一个 vector<int> a,程序会输出 std::vector<int, std::allocator<int> >。这就是人能看懂的形式了。其他的 STL 也类似。

C++ 输出 CPU 型号(Linux)

众所周知 LOJ 有两个评测机,一个是光速的 5800X,另一个是龟速的 G7400其实所谓的龟速比某校内 OJ 好的不是一点

void getCpuInfo() {
    FILE *fp = fopen("/proc/cpuinfo", "r");
    if(NULL == fp)
        printf("failed to open cpuinfo\n");
    char szTest[1000] = {0};
    // read file line by line
    while(!feof(fp)) {
        memset(szTest, 0, sizeof(szTest));
        fgets(szTest, sizeof(szTest) - 1, fp); // leave out \n
        printf("%s", szTest);
    }
    fclose(fp);
}
posted @   Laoshan_PLUS  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示