回来了一本算法竞赛进阶指南。可喜可贺,可喜可贺。
于是怀揣着期末考试GG的决心,我….开刷了(x)
顺便一提。。打*的题太丧病了所以就不做了。。
基本概念
bit是度量信息的基本单位。
0x表示16进制,0xff代表-1,0x7f代表128。
在m位二进制中,从右到左最低位为第0位,最高位为第m-1位。
我们常用0x3f3f3f3f表示最大值,因为二倍是int最大整数,每8位相同。
memset语句只能赋值出每8位相同的int,memset(a, 0x3f, sizeof a)可以用来初始化成最大值。
补码能比反码多表示一个数,减少了特殊判断,在电路设计中很简洁。
1<<n1<<n表示2n2n,n<<1n<<1表示n×2n×2,n>>1n>>1表示⌊n2.0⌋⌊n2.0⌋
所以我学了啥
位运算优先级:
+ - >> << >> > < == != >> & ^ >> |
快速幂与慢速乘
快速幂模板题 POJ1995
#include <iostream>
using namespace std;
typedef long long LL;
LL T, n, m, qwq, tmpa, tmpk, ans;
inline LL ksmqm(LL a, LL k, LL mod) {
LL ans = 1;
for(; k; k >>= 1) {
if(k & 1) ans = ans * a % mod;
a = a * a % mod;
}
return ans;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>T;
while(T--) {
ans = 0;
cin>>m;
cin>>n;
while(n--) {
cin>>tmpa>>tmpk;
ans = (ans + ksmqm(tmpa, tmpk, m)) % m;
}
cout<<ans<<endl;
}
return 0;
}
慢速乘法
法一:对b二进制拆分然后跑一遍快速幂,
法二:玄学的过程?
LL mul(LL a, LL b, LL p){
a %= p, b %= p;
LL c = (long double) a * b - c * p;
LL ans = a * b - c * p;
if(ans < 0) ans += p;
else if(ans >= p) ans -= p;
}
二进制状态压缩
取出第k位 (n >> k) & 1
取出后k位 n & ((1 << k) - 1)
取反第k为 n ^ (1 << k)
第k位赋值1 n | (1 << k)
第k位赋值0 n & (~(1 << k))
例题
例二状压DP。。。
POJ2288打了*先不讨论
Hamilton路径
求从节点0到节点n - 1的最短Hamilton路径。其中Hamilton路径指从1~n恰好不重不漏的经过每个节点一次。n≤20n≤20
状态设计:用dp[s][i]表示在节点i处状态为s,s的每一位分别指代某个节点是否访问过。
初始化:dp[s][i] = INF, dp[1][0] = 0表示从起点出发的路一开始长度是0。
转移:dp[s][i] = min{dp[s ^ (1 << j)][k] + w[k][j]},其中k、j已访问过(用i >> j & 1即可判断),表示从j节点没有被访问过的情况转移到这里。
结果:dp[(1 << n ) - 1][n - 1],表示终点处且每个点都访问过的情况。
复杂度O(n2⋅2n)O(n2⋅2n)
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3fffff
int w[26][26];
int dp[1 << 20][20];
int n, m, f, t, va;
int main() {
scanf("%d%d", &n, &m);
memset(w, 0x3f, sizeof w);
for(int i = 1; i <= m; ++i) {
scanf("%d%d%d", &f, &t, &va);
--f; --t;
w[f][t] = va;
w[t][f] = va;
}
memset(dp, 0x3f, sizeof dp);
dp[1][0] = 0;
int M = 1 << n;
for(int i = 1; i < M; ++i) {
for(int j = 0; j < n; ++j)
if(i >> j & 1)
for(int k = 0; k < n; ++k)
if(i >> k & 1)
dp[i][j] = min(dp[i][j], dp[i ^ 1 << j][k] + w[k][j]);
}
cout<<dp[M - 1][n - 1];
return 0;
}
/*
4 5
1 2 6
2 3 7
0 3 5
1 3 1
2 0 2
*/
其它运算
成对变换:
n为偶数,n ^ 1为n + 1
n位奇数,n ^ 1为n - 1
lowbit:
inline int lowbit(int x) {return x & -x;}
用来取出最低位的1及其后面的0构成的数值。
原理好麻烦的样子(x
本文介绍了位运算的基础知识,包括二进制表示、位运算符的优先级等,并通过快速幂算法和状态压缩DP的经典题目进行实践应用。此外,还探讨了如何利用位运算解决Hamilton路径问题。

182

被折叠的 条评论
为什么被折叠?



