[练习记录] 《算法竞赛进阶指南》打卡活动

89. a^b

题目大意

\(a,b,p\)\(a^b \mod p\)

思路

可以直接快速幂。当模数 \(p\)\(1\) 的时候特判一下。

代码

ll a, b, mod;
ll qpow(ll a, ll b) {
	ll res = 1;
	while (b) {
		if (b & 1) res = res * a % mod;
		a = a * a % mod, b >>= 1;
	}
	return res;
}
int main() {
	a = read(), b = read(), mod = read();
	if (mod == 1) printf("0\n");
	else printf("%lld\n", qpow(a, b));
	return 0;
}

AcWing 90. 64位整数乘法

题目大意

\(a,b,p\)\(a \times b \mod p\)

思路1

好像是想让我写龟速乘,但是我直接 __int128 莽过去了()。

代码1

__int128 a, b, mod;
void prt(__int128 x) {
    if (x > 9) prt(x / 10);
    putchar(x % 10 + '0');
}
int main() {
	a = read(), b = read(), mod = read();
    __int128 ans = a * b % mod;
    prt(ans);
	return 0;
}

思路2

龟速乘,长得和快速幂很像。

代码2

ll a, b, mod;
ll mul(ll a, ll b) {
    ll res = 0;
    while (b) {
        if (b & 1) res = (res + a) % mod;
        a = (a << 1) % mod, b >>= 1;
    }
    return res;
}
int main() {
	a = read(), b = read(), mod = read();
    printf("%lld\n", mul(a, b));
	return 0;
}

91. 最短Hamilton路径

题目大意

给一张 \(n\) 个点的带权无向完全图,求从 \(1\)\(n\) 恰好经过所有点 \(1\) 次的路径的最短长度。

思路

注意到 \(n\leq 20\),考虑状压dp。

设状态 \(f_{i,s}\) 表示经过了状态为 \(s\) 的点,目前在点 \(i\) 处的路径的最短长度。

那么转移很显然 \(f_{j,s|(1<<j)}=\min(f_{j,s|(1<<j)},f_{i,s}+e_{i,j})\),其中 \(i\)\(s\) 状态中被访问过,\(j\) 没有。

代码

const int N = 21, INF = 0x3f3f3f3f;
int n, a[N][N];
int f[N][1 << N];
int main() {
    n = read();
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            a[i][j] = read();
    memset(f, 0x3f, sizeof(f));
    f[1][1] = 0;
    for (int s = 0; s < 1 << n; s++)
        for (int i = 1; i <= n; i++) {
            if ((s & (1 << (i - 1))) == 0) continue;
            for (int j = 1; j <= n; j++) {
                if (s & (1 << (j - 1)) == 1) continue;
                f[j][s | (1 << (j - 1))] = min(f[j][s | (1 << (j - 1))], f[i][s] + a[i][j]);
            }
        }
    printf("%d\n", f[n][(1 << n) - 1]);
	return 0;
}

998. 起床困难综合症

题目大意

给出一系列 \(AND,OR,XOR\) 操作,求 \(0\) ~ \(m\) 内的数经过操作后得到的结果的最大值。

思路

按位填。

代码

const int N = 100010;
int n, m, op[N], t[N], ans;
int calc(int x, int w) {
    for (int i = 0; i < n; i++) {
        if (op[i] == 1) x |= (t[i] >> w) & 1;
        if (op[i] == 2) x ^= (t[i] >> w) & 1;
        if (op[i] == 3) x &= (t[i] >> w) & 1;
    }
    return x;
}
int main() {
    n = read(), m = read();
    for (int  i = 0; i < n; i++) {
        string s; cin >> s;
        if (s == "OR") op[i] = 1;
        if (s == "XOR") op[i] = 2;
        if (s == "AND") op[i] = 3;
        t[i] = read();
    }
    for (int i = 29; i >= 0; i--) {
        if (1 << i > m) {
            ans |= calc(0, i) << i;
            continue;
        }
        int x = calc(0, i), y = calc(1, i);
        if (x >= y) ans += x << i;
        else ans += y << i, m -= 1 << i;
    }
    printf("%d\n", ans);
	return 0;
}

92. 递归实现指数型枚举

题目大意

给出 \(n\),输出所有 \(1\) ~ \(n\) 的升序选取方案。

思路

直接dfs。

代码

const int N = 21;
int n;
int ans[N], cnt;
void dfs(int x) {
    if (x > n) {
        for (int i = 1; i <= cnt; i++) printf("%d ", ans[i]);
        puts("");
        return ;
    }
    ans[++cnt] = x;
    dfs(x + 1);
    cnt--;
    dfs(x + 1);
}
int main() {
	n = read();
    dfs(1);
	return 0;
}

93. 递归实现组合型枚举

题目大意

输出从 \(1\) ~ \(n\) 中选取 \(m\) 个的所有方案。

思路

按题目名称递归求。

代码

const int N = 25;
int n, m;
int ans[N], cnt;
void dfs(int x) {
    if (cnt == m) {
        for (int i = 1; i <= cnt; i++) printf("%d ", ans[i]);
        puts("");
        return ;
    }
    if (x > n) return ;
    ans[++cnt] = x;
    dfs(x + 1);
    cnt--;
    dfs(x + 1);
}
int main() {
    n = read(), m = read();
    dfs(1);
	return 0;
}

94. 递归实现排列型枚举

题目大意

输出 \(1\) ~ \(n\) 的全排列。

思路

暴力dfs。

代码

const int N = 11;
int n;
int ans[N];
bool used[N];
void dfs(int x) {
    if (x > n) {
        for (int i = 1; i <= n; i++) printf("%d ", ans[i]);
        puts("");
        return ;
    }
    for (int i = 1; i <= n; i++) {
        if (used[i]) continue;
        used[i] = 1;
        ans[x] = i;
        dfs(x + 1);
        used[i] = 0;
    }
}
int main() {
	n = read();
    dfs(1);
	return 0;
}
posted @ 2023-04-29 15:25  shiranui  阅读(23)  评论(0编辑  收藏  举报
*/