国庆板子
前言
对拍模板bat
@echo off
:loop
D:/LSNU/codeforces/code/MakeData.exe
D:/LSNU/codeforces/code/A.exe
D:/LSNU/codeforces/code/force.exe
fc AC.txt WA.txt
if not errorlevel 1 goto loop
pause
:end
说明
模板
//#pragma comment(linker,"/STACK:1024000000,1024000000")
//#pragma GCC optimize(2)
//#pragma GCC target ("sse4")
#include<bits/stdc++.h>
//typedef long long ll;
#define ull unsigned long long
//#define int __int128
#define int long long
#define F first
#define S second
#define endl "\n"//<<flush
#define eps 1e-6
#define base 131
#define lowbit(x) (x&(-x))
#define db double
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define MAXN 0x7fffffff
#define INF 0x3f3f3f3f3f3f3f3f
#define ferma(a,b) pow(a%b,b-2)
#define mod(x) (x%mod+mod)%mod
#define pb push_back
#define decimal(x) cout << fixed << setprecision(x);
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define memset(a,b) memset(a,b,sizeof(a));
#define IOS ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
template<typename T> inline T fetch(){
T ret;cin >> ret;return ret;}
template<typename T> inline vector<T> fetch_vec(int sz){
vector<T> ret(sz);for(auto& it: ret)cin >> it;return ret;}
template<typename T> inline void makeUnique(vector<T>& v){
sort(v.begin(), v.end());v.erase(unique(v.begin(), v.end()), v.end());}
template<typename T> inline T max_(T a,T b){
if(a>b)return a;return b;}
template<typename T> inline T min_(T a,T b){
if(a<b)return a;return b;}
void file()
{
#ifdef ONLINE_JUDGE
#else
freopen("D:/LSNU/codeforces/duipai/data.txt","r",stdin);
freopen("D:/LSNU/codeforces/duipai/WA.txt","w",stdout);
#endif
}
signed main()
{
IOS;
file();
return 0;
}
避免万能头文件
#include <algorithm> //STL通用算法
#include <bitset> //STL位集容器
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex> //复数类
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque> //STL双端队列容器
#include <exception> //异常处理类
#include <fstream>
#include <functional> //STL定义运算函数(代替运算符)
#include <limits>
#include <list> //STL线性列表容器
#include <map> //STL 映射容器
#include <iomanip>
#include <ios> //基本输入/输出支持
#include<iosfwd> //输入/输出系统使用的前置声明
#include <iostream>
#include <istream> //基本输入流
#include <ostream> //基本输出流
#include <queue> //STL队列容器
#include <set> //STL 集合容器
#include <sstream> //基于字符串的流
#include <stack> //STL堆栈容器
#include <stdexcept> //标准异常类
#include <streambuf> //底层输入/输出支持
#include <string> //字符串类
#include <utility> //STL通用模板类
#include <vector> //STL动态数组容器
#include <cwchar>
#include <cwctype>
基础算法
关于加速器问题:
ios::sync_with_stdio(false);
是C++的输入输出流(iostream)是否兼容C的输入输出(stdio)的开关。
因为C++中的std :: cin和std :: cout为了兼容C,保证在代码中同时出现std :: cin和scanf或std :: cout和printf时输出不发生混乱,所以C++用一个流缓冲区来同步C的标准流。通过std :: ios_base :: sync_with_stdio函数可以解除这种同步,让std :: cin和std :: cout不再经过缓冲区,自然就节省了许多时间。
副作用:当设置为false时,cin就不能和scanf,sscanf, getchar, fgets等同时使用。
据说,endl用”\n”代替和cout使用,也可节约时间。
cin.tie(0);
因为std :: cin默认是与std :: cout绑定的,所以每次操作的时候(也就是调用”<<”或者”>>”)都要刷新(调用flush),这样增加了IO的负担,通过tie(nullptr)来解除std :: cin和std :: cout之间的绑定,来降低IO的负担使效率提升。
不AC各种情况
TLE:
1:多组测试案例,输入到文本结束
2:多组测试案例,数组一定要清空
3:1左移移动一定要1LL(交互题死过一次)
MLE:
1:每个函数是否有返回值。(线段树死过一次)
WA:
1:定义变量:注意要一个全局跟一个局部相同,意想不到得错误
2:顶点数一定要开双倍
double
避免卡精度:能用加减乘,绝对不用除法
Codeblocks编译器问题
1:数组越界,任然可以计算,不会报错
2:int函数无返回值,任然可以返回,不会报错。
卡常
1:i++
换成++i
2:函数尽量手撸的,例如被max过
3:函数用inline
4:理论int比long long快,有的时候有起效。被n3卡过
5:尽量用if
,不用? :
三目运算符
再不过,🕊,还不明白吗,你的算法烂透了,洗吧脸也没用,奇迹不可能发生了
交互题
前提:自带刷新缓冲流:<<
>>
endl
,本人都已经关闭了,打开其中一个即可。
1:屏蔽cin.tie(0);
,保证std::cin
与sd::cout
绑定:<<
or >>
具有flush效果。
2:格式要求严格,空白符不能多也不能少
高精度
快速乘法,防止爆精度,同时也可以观察是否爆了精度
注意:不能万能的,比如1e15*1e15就暴了,还是注意精度把握和算法的弱点
注意多了一个logn
const int mod=1e15;
int mul(int a,int b)
{
int res=0;
while(b)
{
if(b&1)
res=(res+a)%mod;
a=(a*2)%mod;
b>>=1;
}
return res;
}
快速幂,主要用于是否爆了long long,幂次方很恐怖(CF被高精度坑过一次)
int pow(int a,int b)
{
int ans=1;
while(b)
{
int te=ans;
if(b&1)
ans=ans*a;
if(te>ans)
{
ans=INF;
break;
}
a=a*a;
b>>=1;
}
return ans;
}
快读(一定不要关闭同步流)
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
快输(高精度,__int128,本地无法编译)
如果编译失败,记得用最新的编译器,最好各种编译器试一遍,CF上C17-64BIT,牛客C14就够了
inline void write(__int128 x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar('0'+x%10);
}
PY
num=int(input())///输入整型,任何大
s=input()//输入字符串
ans=""
n=len(s)//计算字符串长度
for i in range(n):
if s[i]=='(':
ans+="**"
ans+=s[i]
print(eval(ans))///特别函数,好用
基础算法
一般ACM或者笔试题的时间限制是1秒或2秒。
在这种情况下,C++代码中的操作次数控制在 1e7 为最佳。
下面给出在不同数据范围下,代码的时间复杂度和算法该如何选择:
1:n≤30, 指数级别, dfs+剪枝,状态压缩dp
2:n≤1e2 => O(n3),floyd,dp
3:n≤1e3 => O(n2),O(n2logn),dp,二分
4:n≤1e4 => O(n∗√n),块状链表
5:n≤1e5 => O(nlogn) => 各种sort,线段树、树状数组、set/map、heap、dijkstra+heap、spfa、求凸包、求半平面交、二分
6:n≤1e6 => O(n)O, 以及常数较小的 O(nlogn) 算法 => hash、双指针扫描、并查集,kmp、AC自动机,常数比较小的 O(nlogn)O(nlogn) 的做法:sort、树状数组、heap、dijkstra、spfa
7:n≤1e7 => O(n),双指针扫描、kmp、AC自动机、线性筛素数
8:n≤1e9 => O(√n),判断质数
9:n≤1e18 => O(logn),最大公约数
1MB=1024KB
1KB=1024B
1B=8bit
Int =48bit
Int a[1e6]=1e648bit=1e6b4=1e3kb4=1mb4
位运算
a+b=a⊕b+2∗ (a&b)
bitset用法
定义:
#include <bitset>
bitset<4> a; // 长度为4,全为零
bitset<4> a("1001"); // 长度为4,1001
用法
a.size() // 返回位数
a.count() // 返回1的个数
a.any() // 返回是否有1
a.none() // 返回是否没有1
a.set() // 重置为1
a.set(pos)
a.reset() // 重置为0
a.reset(pos)
a.set(pos) // 将pos下标设为1,(从低位开始计算)
a.flip() // 全部取反
a.flip(pos)
a.to_ulong() // 转化为unsigned long
a.to_ullong() // 转化为unsigned longlong
a.to_string() // 转化为string
单调栈
维护某一个点比它小于(等于)的第一个数
将一个元素插入单调栈时,为了维护栈的单调性,需要在保证将该元素插入到栈顶后整个栈满足单调性的前提下弹出最少的元素。
例如,栈中自顶向下的元素为1,3,5,10,30,50 ,插入元素 20 时为了保证单调性需要依次弹出元素 1,3,5,10,操作后栈变为 20,30,50 。
insert x
while !sta.empty() && sta.top()<x
sta.pop()
sta.push(x)
单调队列
维护区间最值
set平衡树二分
Set二分,只能得到迭代器,不能相减获取索引,毕竟不是线性结构
multiset<int>se;
auto it=se.lower_bound(it.l);///一定要用上面的
auto jt=lower_bound(se.begin(),se.end(),it.l);///T过
struct node
{
int value,pos;
bool operator<(const node &b)const
{
return value<b.value;
}
};
set<node>se;
signed main()
{
IOS;
// file();
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
int x,value=INF,pos;
cin>>x;
auto it=se.lower_bound({
x,0});
if(it!=se.end())
value=(*it).value-x,pos=(*it).pos;
if(it!=se.begin())
{
it--;
int num1=x-(*it).value,num2=(*it).pos;
if(num1<=value)
value=num1,pos=num2;
}
if(i!=1)
cout<<value<<" "<<pos<<endl;
se.insert({
x,i});
}
return 0;
}
三分
三分的性质:一个区间最多一个递增区间段,一个区间最多一个递减区间段
int l=0,r=1e9;
while(r-l>10)
{
int midl=l+(r-l)/3;
int midr=r-(r-l)/3;
int numl=check(midl),numr=check(midr);
if(numl>numr)
l=midl;
else
r=midr;
}
int ans=INF;
for(int i=l;i<=r;i++)
ans=min(ans,check(i));
cout<<ans<<endl;
数被整除
重载无序STL容器
本质非基本类型,不存在hash函数,无法进行hash
class Myclass
{
public:
int first;
int second;
// 重载等号,判断两个Myclass类型的变量是否相等
bool operator== (const Myclass &other) const
{
return first == other.first && second == other.second;
}
};
// 实现Myclass类的hash函数
namespace std
{
template <>
struct hash<Myclass>
{
size_t operator()(const Myclass &k) const
{
///自己手写hash方法
return k.first+k.second;
}
};
}
List用法,双向链表
list 由双向链表(doubly linked list)实现而成,元素也存放在堆中,每个元素都是放在一块内存中,他的内存空间可以是不连续的,通过指针来进行数据的访问,这个特点使得它的随机存取变得非常没有效率,因此它没有提供 [] 操作符的重载。但是由于链表的特点,它可以很有效率的支持任意地方的插入和删除操作。
优势:删除与添加常数操作,相对vector是线性得。
1 容量函数
容器大小:lst.size();
容器最大容量:lst.max_size();
更改容器大小:lst.resize();
容器判空:lst.empty();
2 添加函数
头部添加元素:lst.push_front(const T& x);
末尾添加元素:lst.push_back(const T& x);
任意位置插入一个元素:lst.insert(iterator it, const T& x);
任意位置插入 n 个相同元素:lst.insert(iterator it, int n, const T& x);
插入另一个向量的 [forst,last] 间的数据:lst.insert(iterator it, iterator first, iterator last);
3 删除函数
头部删除元素:lst.pop_front();
末尾删除元素:lst.pop_back();
任意位置删除一个元素:lst.erase(iterator it);
删除 [first,last] 之间的元素:lst.erase(iterator first, iterator last);
清空所有元素:lst.clear();
4 其他函数
多个元素赋值:lst.assign(int nSize, const T& x); // 类似于初始化时用数组进行赋值
交换两个同类型容器的元素:swap(list&, list&); 或 lst.swap(list&);
合并两个列表的元素(默认升序排列):lst.merge();
在任意位置拼接入另一个list:lst.splice(iterator it, list&);
删除容器中相邻的重复元素:lst.unique();
螺旋矩阵n2
long long index(long long y, long long x, long long n)
{
long long mid = (n + 1) / 2;
long long p = max(abs(x - mid), abs(y - mid));
long long ans = n * n - (1 + p) * p * 4;
long long sx = mid + p, sy = mid + p;
if (x == sx && y == sy) {
return ans;
} else {
if (y == sy || x == sx - 2 * p) {
return ans + abs(x - sx) + abs(y - sy);
} else {
return ans + 8 * p - abs(x - sx) - abs(y - sy);
}
}
}
开根号
n m \sqrt[m]{n} mn
pow(n,1.0/m)
退火模拟
随机概率算法,我觉得玄学,朋友说99%过,反正默认了吧
void SA()
{
double T=3000;
double D=0.99551748;
double cur_ans=ans;
while(T>1e-9)
{
int l=rand()%n,r=rand()%n;
swap(a[l],a[r]);
double now=cal();
ans=min(ans,now);
double dif=now-cur_ans;
if(dif<0)///当前ans不断逼近minimize
cur_ans=now;
else if(exp(-dif/T)*RAND_MAX>rand())///指数增长接受更bad cur_ans
cur_ans=now;
else
swap(a[l],a[r]);
T*=D;///降温
}
}
卡时,骗分神器
void fire()
{
clock_t s;
s=clock();
double usedtime=0;
while(usedtime<0.75)
{
cal();
usedtime=double(clock()-s)/CLK_TCK;
// cout<<usedtime<<endl;
//CLK_TCK=1e6
}
}
数论
欧几里得算法证明 O( logn )
gcd
求A和B的最大公约数
假设X为最大公约数
间接条件:X | A X | B
假设A >= B
建立方程式A + KB = C = A % B
∵ X | A X | KB
∴ X | A + KB
∴ X | C
∴ GCD(A,B)== GCD(B, A%B)
然后我们就可以不断的往下辗转相除
求GCD(B,C)
B和C最大公约数也是X
何时是个头
GCD(KX , X )其实这里能被整除,就已经知道求到GCD了
再往下
GCD (X , 0)
扩展欧几里得 O( logn )
exgcd
前提条件:d==gcd(a,b)
问题:ax+by=d,求x和y的通解
那么我们先建立一个方程组
A:ax1 + by1= d ==gcd(a,b)
B:bx2 + a%by2= d ==gcd(b,a%b)
B方程式展开:bx2 + ( a - a / b * b ) * y2=d
括号打开再合并:ay2 + b * ( x2 - a / b * y2 ) = d
所以:
x1=y2
y1=x2 - a / b * y2
不断递归下去到头
ax + 0*y = gcd(a,0);
所以x=1,y=0;
ax+by=c
如果 d | c 一定有解,否则一定无解
注意1:
exgcd求得是c == d的x,y
x= x * c/d, y = y * c/d;
这里才是正式的ax+by=c的x与y的一组解。
注意2:
exgcd求到得x,可能为负数,所以不断得加最小系数k1和减去k2
a * ( x + k1 )+ b * ( y - k2 )=d
展开后,保证a * k1= =b * k2 = = lcm(a,b)
所以 k1= lcm(a,b) / a , k2 = lcm(a,b)/b;
然后加成正数就行,但是不是最小正数,x>=k1,就得不断减去k1;
第一步:先求exgcd的,x,y
第二步:看是否需要加系数k1,k2
int exgcd(int a,int b,int &x1,int &y1)///求到c==gcd的一个x与y的解
{
if(b==0)
{
x1=1,y1=0;
return a;
}
int x2,y2;
int gcd=exgcd(b,a%b,x2,y2);
x1=y2,y1=x2-a/b*y2;
return gcd;
}
x=(x%k1+k1)%k1;///这一步才是最小的正整数x,x>=k1,要降,x<0,要增加。
多项式
在数学中,由若干个单项式相加组成的代数式叫做多项式(若有减法:减一个数等于加上它的相反数)。多项式中的每个单项式叫做多项式的项,这些单项式中的最高项次数,就是这个多项式的次数。其中多项式中不含字母的项叫做常数项。
本原多项式
高斯引理:本原多项式的乘积还是本原多项式。
(证明就算了吧,我不配)
组合数
n个不同物品的排列数A(n,n)=A!(原理:加法原理+乘法原理)
公式:A(n,n)=n*(n-1)(n-2)···(n-n+1)=A!
变形一下:
从n个不同物品取m个的排列数:A(n,m)
公式:A(n,m)=n*(n-1)*(n-2)···(n-m+1);
从n个不同物品取m个的组合数:C(n,m)
公式:C(n,m)=A(n,m)/A(m,m)=n!/(n-m)!/m!;
这里提一下A(n,m)=P(n,m),只不过P是老版教材的用法
C n m = n ! m ! ∗ ( n − m ) ! C^m_n=\frac{n!}{m!*(n-m)!} Cnm=m!∗(n−m)!n!
递推公式:
C n m = C n − 1 m + C n − 1 m − 1 C^m_n=C^m_{n-1}+C^{m-1}_{n-1} Cnm=Cn−1m+Cn−1m−1
性质1:
C n m = C n n − m C^m_n=C^{n-m}_n Cnm=Cnn−m
性质2:
C n + m + 1 m = ∑ i = 0 m C n + i i C^m_{n+m+1}=\sum^m_{i=0}{C^i_{n+i}} Cn+m+1m=i=0∑mCn+ii
性质3:
C n m ∗ C m r = C n r ∗ C n − r m − r C^m_n *C^r_m=C^{r}_n *C^{m-r}_{n-r} Cnm∗Cmr=Cnr∗Cn−rm−r
性质4:(二项式定理)
∑ i = 0 n C n i = 2 n \sum^n_{i=0}{C^i_n}=2^n i=0∑nCni=2n
性质5:(n为奇数,产生偶数个)
C n 0 − C n 1 + C n 2 − C n 3 … … C n n = 0 C^0_n-C^1_n+C^2_n-C^3_n……C^n_n=0 Cn0−Cn1+Cn2−Cn3……Cnn=0
性质6:(根据性质4和性质5,并且m为奇数)
C n 0 + C n 2 + C n 4 … … = C n 1 + C n 3 + C n 5 … … = 2 n − 1 C^0_n+C^2_n+C^4_n……=C^1_n+C^3_n+C^5_n……=2^{n-1} Cn0+Cn