校赛

1. 二分

小数

    double l = 0,r = 100000,eps = 1e-4;
	while (r-l >= eps){
		double mid=(l+r)/2;
		if (check(mid)) l=mid;
		else r=mid;
	}

整数

    int l = 1,r = n,mid = (l+r)>>1;
	while (l<r){
		mid = (l+r+1)>>1;
		if (check(mid)) l = mid;
		else r = mid-1;
	}

2. 并查集

O(logn)

int init(){
   for (int i = 1;i <= n;i++) fa[i] = i;
}
int find(int x){
   if (fa[x] == x) return x;
   return fa[x] = find(fa[x]);
}
void update(int x,int y){
  int fu = find(x),fv = find(y);
  fa[fu] = fv;
}

3. 递推

01背包

for (int i = 1;i <= n;i++) for (int j = m;j >= 0;j--) if (j >= w[i]) dp[j] = max(dp[j],dp[j-w[i]]+v[i]);

完全背包

for (int i = 1;i <= n;i++) for (int j = 0;j <= m;j++) if (j >= w[i]) dp[j] = max(dp[j],dp[j-w[i]]+v[i]);

多重背包

for (int i = 1;i <= n;i++) for (int j = m;j >= 0;j--) for (int k = 1;k <= num[i];k++){
  if (j >= w[i]*k) dp[j] = max(dp[j],dp[j-k*w[i]]+k*v[i]);
}

多重背包的优化:把一个物品的不同个数(这里是\(2^n\))看成是不同物品,然后01背包

int totlW = 0;
memset(w,0,sizeof w);
for (int i = 1;i <= n;i++){
    for(int j = 1;j <= num[i];j <<= 1){
        w[totlW++] = j * weight[i];
        num[i] -= j;
    }
    if(num[i] > 0) w[totlW++] = num[i] * weight[i];
}

4. gcd

O(2log(max(a,b)))

int gcd(int a,int b){
  if (!b) return a;
  return gcd(b,a % b);
}

5. 最短路

Dij:Dij还可以用来计算多源最短路,只需要将每个起点都放入最初的队列

O(mlogn)

struct node{
	int tot = 0;
	int head[maxn],to[maxn],nxt[maxn];
	long long w[maxn];
	void add(int u,int v,int k){
		to[++tot] = v,w[tot] = k,nxt[tot] = head[u],head[u] = tot;
	}
}ed;
long long dis[maxn];
bool vis[maxn];
priority_queue<pair<long long,int> > q;
void Dij(){
	for (int i = 1;i <= n;i++) dis[i] = inf,vis[i] = 0;
	dis[s] = 0;
	q.push(make_pair(0,s));
	while (!q.empty()){
		int x = q.top().second;q.pop();
		if (vis[x]) continue;
		vis[x] = 1;
		for (int i = ed.head[x];i;i = ed.nxt[i]){
			int to = ed.to[i];
			if (dis[to] > dis[x] + ed.w[i]) {
				dis[to] = dis[x] + ed.w[i];
				q.push(make_pair(-dis[to],to));
			}
		}
	}
}

SPFA:SPFA判负环,如果一个点入队n次则有负环

O(nm)

void SPFA(){
	for (int i = 1;i <= n;i++) dis[i] = inf;
	dis[s] = 0,vis[s] = 1;
	q.push(s);
	while (!q.empty()){
		int x = q.front();q.pop();
		vis[x] = 0;
		for (int i = ed.head[x];i;i = ed.nxt[i]){
			int to = ed.to[i],w = ed.w[i];
			if (dis[to] > dis[x] + w){
				dis[to] = dis[x] + w;
				if (!vis[to]){
					vis[to] = 1;
					q.push(to);
				}
			}
		}
	}
}

Floyd

void Floyd(){
	for (int k = 1;k <= n;k++) 
		for (int i = 1;i <= n;i++) 
			for (int j = 1;j <= n;j++) dis[i][j] = min(dis[i][j],dis[i][k]+dis[k][j]);
} 

6. 广度优先搜索

找最短路径,如果有特殊限制可能需要优先队列

7. 深度优先搜索

注意:多找剪枝的情况,记忆化搜索

8. 二分图匹配

O(顶点数*边数)

最大匹配:

int dfs(int x){
	for (int i = 1;i <= k;i++){
		if (!edge[x][i]) continue;
		if (vis[i]) continue;
		vis[i] = 1;
		if (!match[i]||dfs(match[i])){
			match[i] = x;
			return 1;
		}
	}
	return 0;
}

	memset(match,0,sizeof(match));
	for (int i = 1;i <= n;i++){
		memset(vis,0,sizeof(vis));
		if (dfs(i)) ans++;
	}

最小点覆盖 = 最大匹配:选取最少的点,使得所有边都至少与一个被选取点相连

最大独立集 = 总点数 - 最大匹配:选取最多的点,使得其中任意两点互不相达

最小边覆盖 = 总点数 - 最大匹配:选取最少的边使得所有的点被至少一条边覆盖

9. 博弈

可以数学推导,也可以打表SG函数算

SG函数:先打表求出一定范围内每个小状态的SG值,发现规律后(发现不了规律可以硬算),总状态的SG值为每个小状态的SG值的异或和,为0就是第一个人输了

map<pair<int,int>,int> mp;
int getSG1(int a,int b){
	bool vis[maxn];
	if (mp.count(make_pair(a,b))) return mp[make_pair(a,b)];
	memset(vis,0,sizeof(vis));
	for (int i = 1;i < a;i++) vis[getSG1(i,a-i)] = 1;
	for (int i = 1;i < b;i++) vis[getSG1(i,b-i)] = 1;
	for (int i = 0;i <= 10000;i++) if (!vis[i]){mp[make_pair(a,b)] = i;break;}
	return mp[make_pair(a,b)];
}

10. 一些STL的用法

存储结构体要重载运算符

struct node{
	int x = 0,y = 0;
	bool operator < (const node &a)const{
		if (x != a.x) return x < a.x;
		return y < a.y;
	} 	
}fig[maxn];

set 集合:有序不重复/unordered_set:只去重不排序/multiset:有序可重

s.insert();
s.clear();
set<int>::iterator it = s.find();
s.erase(s.find());//删除这个位置
s.erase(value);//删除一个值
s.erase(s.find(),s.find())//删除一个区间
s.size();
s.count();//某个值出现了多少次
set<int>::iterator it_low = st.lower_bound("i");//第一个大于等于
set<int>::iterator it_up = st.upper_bound("i");//第一个大于
for (set<int>::iterator it = s.begin();it != s.end();it++){
	printf("%d ",*it);
}

map/unorderd_map/multimap

这里需要注意mulitmap只支持mp.insert(pair<int,string>(1,"ssss"));

if (mp.find(x) != mp.end())

11. 快速幂

int qpow(int x,int k){
	int res = 1;
	while (k){
		if (k&1) (res *= x) %= mod;
		(x *= x) %= mod;
		k >>= 1;
	}
	return res % mod;
}

矩阵快速幂

可以用作dp优化,我们通常把dp[i]构造出一个\(n\times1\)的矩阵,转移矩阵为n\(\times\)n,如斐波那契:

struct mul{
    long long a[maxn][maxn];
}a,I;
mul operator *(const mul &x,const mul &y){     //重载运算符
    mul z;
    memset(z.a,0,sizeof(z.a));
    for (int k = 1;k <= n;k++)
        for (int i = 1;i <= n;i++)
            for (int j = 1;j <= n;j++)
                z.a[i][j] = (z.a[i][j] + x.a[i][k]*y.a[k][j] % mod) % mod;
    return z;
}
void qpow(long long k){
	for (int i = 1;i <= n;i++) for (int j = 1;j <= n;j++) I.a[i][j] = 0;
    for (int i = 1; i <= n;i++) I.a[i][i] = 1;
    while(k){
        if (k&1) I = I * a;
        a = a*a;
        k >>= 1;
    }
}

12. 离散化

sort(que+1,que+1+cnt);
len = unique(que+1,que+cnt+1)-que-1;
for(int i = 1;i <= n;i ++){
    s[i] = lower_bound(que + 1, que + len + 1, k[i]) - que;
}
posted @ 2023-11-04 19:39  小又又yyyy  阅读(11)  评论(0编辑  收藏  举报