0x01 基本算法-位运算

A题:a^b

https://ac.nowcoder.com/acm/contest/996/A

题目描述
求 a 的 b 次方对 p 取模的值,其中 0 <= a,b,p <= 10^9

输入描述:
三个用空格隔开的整数a,b和p。

输出描述:
一个整数,表示a^b mod p的值。

实例
输入: 2 3 9
输出: 8

思路
这道题是要先算出a的b次幂再对其结果进行求模(取余),因为b最大可为1e+9,按普通做法来做时间复杂度就太大了,显然这样过不了题,
能快速算a的b次幂,就能减小时间复杂度,快速幂就是一种不错的方法。

什么是快速幂
快速幂是一种简化运算底数的n次幂的算法,理论上其时间复杂度为 O(log₂N),而一般的朴素算法则需要O(N)的时间复杂度。简单来说快速幂其实就是抽取了指数中的2的n次幂,将其转换为时间复杂度为O(1)的二进制移位运算,所以相应地,时间复杂度降低为O(log₂N)。

代码原理
a13 为例,
先把指数13化为二进制就是1101,把二进制数字1101直观地表现为十进制则是如下的等式:

13=1(23)+1(22)+0(21)+1(20)

这样一来 a13 可以如下算出:

a13=a(23)a(22)a(20)

完整AC代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;//将long long类型取个别名:ll类型,为了方便

int power(int a, int b, int mod) {
	ll ans = 1 % mod;
	for (; b; b >>= 1) {
		if (b & 1) ans = ans * a % mod;
		a = (ll)a * a % mod;//显式转化为ll类型进行高精度计算,再隐式转化为int
	}
	return ans;
}

int main() {
	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false), cin.tie(0);
	int a, b, mod;
	cin >> a >> b >> mod;
	cout << power(a, b, mod) << endl;
}

B题:Raising Modulo Numbers

与上面A题写法一样

typedef long long ll;
int _;
// 稍微优化下上方代码:update 21/01/28
ll qpow(ll a, ll b, ll mod) {
    ll ans = 1;
    a %= mod;
    for (; b; a = a * a % mod, b >>= 1)
        if (b & 1) ans = ans * a % mod;
    return ans;
}
int main() {
    // freopen("in.txt", "r", stdin);
    ios_base::sync_with_stdio(false), cin.tie(0);
    ll M, N;
    for (cin >> _; _--;) {
        cin >> M >> N;
        ll a, b, ans = 0;
        while (N--) {
            cin >> a >> b;
            ans = (ans + qpow(a, b, M)) % M;
        }
        cout << ans << endl;
    }
}

C题:64位整数乘法

链接:https://ac.nowcoder.com/acm/contest/996/C

思路:

类似快速幂的思想,把整数b用二进制表示,即

b=ck12k1+ck22k2+...+c020

typedef long long ll;
int main() {
	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false), cin.tie(0);
	ll a, b, p; cin >> a >> b >> p;
	ll ans = 0;
	for (; b; b >>= 1) {
		if (b & 1)ans = (ans + a) % p;
		a = (a << 1) % p;
	}
	cout << ans << endl;
}

⭐D题:最短Hamilton路径

链接:https://ac.nowcoder.com/acm/contest/996/D

解题思路

undefined
image-20200807130325034
image-20200807130325034

AC代码:

#define ms(a,b) memset(a,b,sizeof a)
int e[21][21], b[1 << 21][21], n;
int main() {
	//freopen("in.txt", "r", stdin);
	ios::sync_with_stdio(false), cin.tie(0);
	cin >> n;
	for (int i = 0; i < n; ++i)
		for (int j = 0; j < n; ++j)
			cin >> e[i][j];
	ms(b, 0x3f); b[1][0] = 0;
	for (int i = 0; i < 1 << n; ++i)
		for (int j = 0; j < n; ++j) if (i >> j & 1)
			for (int k = 0; k < n; ++k) if (~(i >> k) & 1)//if ((i ^ 1 << j) >> k & 1)
				b[i + (1 << k)][k] = min(b[i + (1 << k)][k], b[i][j] + e[j][k]);
	cout << b[(1 << n) - 1][n - 1] << endl;
}

⭐例题:[NOI2014]起床困难综合征

题意:

链接:[NOI2014] 起床困难综合症

贪心从高位到低位枚举,检验当前位在初始值为0 情况下的答案是否可以为1 ,如果不能则检验当前位初始值能否为 1,并检验当前位在初始值为 1 情况下的答案是否可以为 1

int n, m, x;
string str;
pair<string, int> a[100005];
int work(int bit, int now) {  // 用参加的第 bit 位进行n次运算
    for (int i = 1; i <= n; ++i) {
        int x = a[i].second >> bit & 1;
        if (a[i].first == "AND")
            now &= x;
        else if (a[i].first == "OR")
            now |= x;
        else
            now ^= x;
    }
    return now;
}
int main() {
    ios_base::sync_with_stdio(false), cin.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        cin >> str >> x;
        a[i] = make_pair(str, x);
    }
    int val = 0, ans = 0;
    for (int bit = 29; bit >= 0; bit--) {
        int res0 = work(bit, 0), res1 = work(bit, 1);
        if (val += (1 << bit) <= m && res0 < res1)
            val += (1 << bit), ans += (res1 << bit);
        else
            ans += (res0 << bit);
    }
    cout << ans << "\n";
    return 0;
}
posted @   RioTian  阅读(542)  评论(0编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 全程不用写代码,我用AI程序员写了一个飞机大战
点击右上角即可分享
微信分享提示

📖目录