zoukankan      html  css  js  c++  java
  • 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)。

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

    \[13 = 1 * (2^3) + 1 * (2^2) + 0 * (2^ 1) + 1 * (2^0) \]

    这样一来 \(a^{13}\) 可以如下算出:

    \[a^{13} = a ^ {(2^3)} * a ^ {(2^2)} * a ^ {(2^0)} \]

    完整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 = c_{k - 1}2^{k - 1} + c_{k -2}2^{k - 2} + ... + c_02^0 \]

    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

    解题思路

    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;
    }
    
  • 相关阅读:
    js字符串使用占位符拼接
    C#解析json字符串总是多出双引号的原因分析及解决办法
    JS 正则验证字符串中是否含有数字
    不错的MVC文章
    Js 更换html同一父元素下子元素的位置
    团队任务个人博客--20160426
    《构建之法》阅读笔记3
    团队任务个人博客20160425
    团队任务个人博客20160424
    软件工程进度条-第八周
  • 原文地址:https://www.cnblogs.com/RioTian/p/13452196.html
Copyright © 2011-2022 走看看