\(\text{Point 1}\)
可以用 memset(f,0x3f,sizeof f)
来给 \(\text{int},\text{long long}\) 极大值赋值,它的两倍也不会爆。
可以用 memset(f,0x7f,sizeof f)
来给 \(\text{int},\text{long long}\) 极大值赋值,不过它的两倍会爆。
可以用 memset(f,0xc0,sizeof f)
来给 \(\text{int},\text{long long}\) 极小值赋值,它的两倍也不会爆。
可以用 memset(f,0x80,sizeof f)
来给 \(\text{int},\text{long long}\) 极小值赋值,不过它的两倍会爆。
\(\text{Point 2}\)
求二进制中 \(1\) 的个数。
方法壹
用 __builtin_popcount(x)
,头文件 #include <cstdio>
。
方法贰
递推有 rep(i,1,n) bit[i]=bit[i-(i&-i)]+1;
。
\(\text{Point 3}\)
二进制枚举子集,假设 \(\rm lim\) 的二进制有 \(n\) 位。
for(int s=0;s<=lim;++s)
for(int i=s;i;i=(i-1)&s)
每次都在减小,而 &s
保证了一定是子集,故正确。
关于时间复杂度就是 \(\mathcal O(3^n)\)。
首先对于有 \(i\) 个 \(1\) 的数,因为枚举是只枚举子集且只枚举一次,时间复杂度就是 \(1\) 可以变成 \(1/0\) 即 \(\mathcal O(2^i)\)。
而我们有 \(C_n^i\) 个这样的数,总时间复杂度为 \(\mathcal O(\sum_{i=0}^n C_n^i\times 2^i\times 1^{n-i})=\mathcal O(3^n)\)。
\(\text{Point 4}\)
这样好像会快一点。
inline int mul(const int x,const int y) {return 1ll*x*y-1ll*x*y/mod*mod;}
\(\text{Point 5}\)
快速判断一个数是否为 \(2\) 的幂。即 ((x-1)&x)=0
.
正负号转换:x = (~x)+1
.
比较数值是否同号:(x^y)>0
.
附加一些 \(\mathtt{qqgg}\) 的数:
\(\text{Point 6}\)
哈希表模板:
struct hash_table {
int head[key],cnt;
struct Edge {
ull val; int to;
} e[maxn];
void Insert(ull x) {
e[++cnt].val=x,e[cnt].to=head[x%key],head[x%key]=cnt;
}
bool Count(ull x) {
for(int i=head[x%key];i;i=e[i].to)
if(e[i].val==x) return 1;
return 0;
}
} mp;
似乎表大小开元素个数 \(4\) 倍比较稳。另外注意求哈希值的时候,选取的模数要远大于方案数。
\(\text{Point 7}\)
- 时间复杂度为 \(\mathcal O(n)\)。
- 数组从 \(1\) 开始时,只用减去数组名。
- 当返回下标时,返回的是原数组的值按照规定排序后 去重 的下标。比如
1 2 3 3 2
。
\(\text{Point 8}\)
\(\rm spfa\) 判断负环(起点 可到达 的负环):存储从起点到达这个点 成功扩展 了几次,如果有 \(n\) 次说明一定存在被经过两次的点,就形成了一个环。考虑我们在求取最短路,如果这个环不是负环就一定不优,所以此图存在负环。
\(\text{Point 9}\)
关于 nth_element()
。求第 \(k\) 小的同时将小的放在左边,大的放右边,保证第 \(k\) 位为第 \(k\) 小。不保证 时间复杂度为 \(\mathcal O(n)\)。
使用方法:nth_element(a+start,a+k,a+end+1)
。还可以自定义排序。
\(\text{Point 10}\)
fep(i,30,0) if(ans+(1<<i)<=1e9 && ok(ans+(1<<i))) ans+=(1<<i);
二分 \(1e9\) 内满足条件的最大值。
\(\text{Point 11}\)
这个 \(\rm trick\) 好像没啥大用(自己应该不会把题目做到需要卡常的分数),但还是想记录下来:比方说计算某个编号在一棵线段树上是第几层的第几个点,显然只用算出小于等于这个数的最大的 \(2\) 的幂。计算这个可以用两种方法:
\(\mathcal O(\log \log n)\)
inline int getId(int o) {
o |= (o>>1);
o |= (o>>2);
o |= (o>>4);
o |= (o>>8);
o |= (o>>16);
return o+1>>1;
}
假设最高位的 \(1\) 在第 \(i\) 位,我们要做的是将后面到第 \(0\) 位都变成 \(1\),这样加一再除二就是答案。
\(\mathcal O(1)\)
预处理出 \(\log_i\),直接 \(2^{\log_i}\) 即可。
\(\text{Point 12}\)
__builtin_ffs(x)
:\(x\) 二进制最后一个 \(1\) 在从右往左数的第几位。
\(\text{Point 13}\)
进行多次取模时,可将变量改成 long long
类型来减少取模次数。
\(\text{Point 14}\)
无限栈:
-Wl,--stack=128000000
忽略空格的 \(\rm checker\):
system("fc /W palin.out palin4.ans")
有的时候,文件输入输出后需要在控制台操作,咋办呢?可以这样写:
int main() {
freopen("data.in","r",stdin);
freopen("result.out","w",stdout);
int a,b;
scanf("%d %d",&a,&b);
printf("%d\n",a+b);
freopen("CON","r",stdin);
freopen("CON","w",stdout);
cin>>a>>b;
printf("%d\n",a+b);
return 0;
}
关闭文件可以用 fclose()
函数。
\(\text{Point 15}\)
遇见 \(n\times m\le 10^5\) 的题目该怎么存下数组呢?
当然是,\(\rm vector\)!T 成什么东西就不用我多说了吧。
事实上,你也可以使用 new
这个玩意。
当然,二维数组可以这样搞:
int **a;
a=new int*[n];
不过好像在 \(\rm Linux\) 环境下写 delete()
会内存超限。
\(\text{Point 16}\)
存一下各种颜色的字体:
<font color= #F8F8FF>写点东西。</font>
另外还有设置图片居中:
<div align=center>
<img src="链接"/>
</div>
\(\text{Point 17}\)
关于 \(\rm bitset\) 的一些函数:
set(x,y)
。将第 \(x\) 位置为 \(y\)。_Find_first()
。从低位到高位找到第一个 \(1\) 的位置。如果没有返回 \(\rm bitset\) 大小。复杂度是 \(\mathcal O(n/w+cnt_1)\)。_Find_next(x)
。就是找到 \(x\) 位置的下一个 \(1\) 的位置。复杂度是 \(\mathcal O(n/w+cnt_1)\)。
\(\text{Point 18}\)
还记得在读入优化中这条语句吗?
while(s>='0' and s<='9')
x=(x<<1)+(x<<3)+(s^48),
s=getchar();
为什么 s^48
能将字符转成数字呢?首先字符 \(0\) 的 \(\rm ASCII\) 码是 \(48=2^5+2^4\),由于字符 \([0,9]\) 远没有达到 \(2^4\) 这一位,所以可以直接异或 \(48\)。
同理,我们可以优化大小写转化。由于 \(a,A\) 的 \(\rm ASCII\) 码分别是 \(97=2^6+2^5+2^0,65=2^6+2^0\),而且 \(26\) 个字母没有 \(32\) 大,所以直接异或 \(32\) 即可。
\(\text{Point 19}\)
使用 \(\rm cmd\) 计算 静态 内存。\(\text{Link.}\)
\(\text{Point 20}\)
有符号整数溢出是未定义行为,较高版本编译器不会考虑这种情况。
可以加个 -fsanitize=undefined
来检测一些未定义行为。
\(\text{Point 21}\)
关于 memcpy(s,begin,len)
。表示从 \(\rm begin\) 开始的地址复制 \(\rm len\) 到 \(s\)。
\(\text{Point 22}\)
吃个 \(\rm fread\)。
char buf[1<<21];
inline char gc() {
static char *S=buf,*T=S;
if(S==T) S=buf,T=S+fread(S,1,1<<21,stdin);
return *(S++);
}
\(\text{Point 23}\)
关于 fgets(char *str,int num,FILE *stream)
:\(\rm str\) 是被拷贝数组的起始指针,\(\rm num\) 是想要读取的元素个数 \(+1\),后面那个用 stdin
即可。
停止条件:
- 拷贝完规定字符。但不到换行符或 \(\text{End Of File}\) 不会停止读入。
- 到换行符或 \(\text{End Of File}\)。
需要注意,如果读入到换行符时未读入完规定字符,会将 \n
插入字符串末并计入长度。
返回值:如果到达文件末尾或者没有读取到任何字符或者发生错误,返回一个空指针 \(\rm null\).
\(\text{Point 24}\)
用 \(\rm cmd\) 编译运行 \(\text{C plus plus}\) 程序:
- 将 \(\rm mingw\) 中的 \(\rm bin\) 设置在系统变量的 \(\rm path\) 中。
- 用
cd
转到目录(可以用cd /d D:\
),然后输入g++ -o name name.cpp -std=c++14
。 - 最后输入
name.exe
。
\(\text{Point 25}\)
有时候乘法取模连 \(\text{unsigned long long}\) 都会溢出。怎么办?龟速乘?
事实上,我们可以运用乘法分配律!
inline ll ksc(ll x, ll y, ll P){
ll L = x*(y>>25)%P*(1<<25)%P;
ll R = x*(y&((1<<25)-1))%P;
return (L+R)%P;
}
\(\text{Point 26}\)
\(\rm vector\) 如何真正释放内存?
vector <TYPE> ().swap(myVector)
\(\text{Point 27}\)
需要注意应该先减去较大值。
\(\text{Point 28}\)
正则表达式删除代码行号:\(\rm Link.\)
\(\text{Point 29}\)
cin.getline(char *str,int num,结束符(char))
:此时 \(\rm num\) 仍然是想要读取的元素个数 \(+1\),但如果读入到结束符时未读入完规定字符也不会插入其它字符。它会用空字符替换结束符。
一个需要注意的点是 cin.getline()
,getline()
,getchar()
等都是在缓冲区读入,这次没读完的下次还会继续读。
再记录一个输入超长的问题:
char a[20];
cin.getline(a,5); // 输入:12345(enter)
cout<<a<<endl;
char ch=getchar();
cout<<ch<<endl;
显然 \(a\) 输出的值是 1234
,但你会发现 \(\rm ch\) 读不进 5
!这是因为 cin.getline()
输入超长时,会引起 cin
函数的错误,后面的 cin
操作将不再执行。解决方法是使用 cin.clear()
,重置错误标志。
getline(FILE *stream,string& str,结束符(char))
:如果读入到结束符时未读入完规定字符也不会插入其它字符。它会用空字符替换结束符。
\(\text{Point 30}\)
偷懒可以直接用 \(\text{pb_ds}\) 里的 \(\text{hash_table}\),用法和 \(\rm map\) 基本相同,但是会快一些:
# include <ext/pb_ds/hash_policy.hpp>
# include <ext/pb_ds/assoc_container.hpp>
然后再用
__gnu_pbds::gp_hash_table <TYPE, TYPE> map;
\(\text{Point 31}\)
存一下在 \(\rm linux\) 环境下的对拍程序。
\(\rm datamaker.cpp\):
# include <cstdio>
# include <cctype>
# define print(x,y) write(x), putchar(y)
template <class T>
inline T read(const T sample) {
T x=0; char s; bool f=0;
while(!isdigit(s=getchar())) f|=(s=='-');
for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
return f? -x: x;
}
template <class T>
inline void write(T x) {
static int writ[50], w_tp=0;
if(x<0) putchar('-'), x=-x;
do writ[++w_tp]=x-x/10*10, x/=10; while(x);
while(putchar(writ[w_tp--]^48), w_tp);
}
# include <unistd.h>
# include <bits/stdc++.h>
using namespace std;
int main() {
usleep(1000.0);
int n=15, tot=0, x; print(n,'\n');
mt19937 SEED(time(0));
uniform_int_distribution <int> mac(0,1);
for(int i=1;i<=(n<<1);++i) {
if((n<<1)-i+1==tot) {
for(int j=1;j<=tot;++j)
putchar('b');
break;
}
while(233) {
x = mac(SEED);
if(tot==0 && x);
else break;
} putchar(x? 'b': 'a');
tot += x? -1: 1;
} puts("");
return 0;
}
\(\rm checker.cpp\):
# include <cstdio>
# include <cctype>
# define print(x,y) write(x), putchar(y)
template <class T>
inline T read(const T sample) {
T x=0; char s; bool f=0;
while(!isdigit(s=getchar())) f|=(s=='-');
for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
return f? -x: x;
}
template <class T>
inline void write(T x) {
static int writ[50], w_tp=0;
if(x<0) putchar('-'), x=-x;
do writ[++w_tp]=x-x/10*10, x/=10; while(x);
while(putchar(writ[w_tp--]^48), w_tp);
}
# include <bits/stdc++.h>
using namespace std;
int main() {
for(int i=1;i<=1000;++i) {
system("./datamaker > data.in");
system("./1 < data.in > 1.out");
system("./2 < data.in > 2.out");
if(system("diff 1.out 2.out"))
{ printf("\033[0m\033[1;31mWrong Answer.\033[0m\n"); return 0; }
else printf("\033[0m\033[1;32mAccepted.\033[0m\n");
}
return 0;
}