• 2005年NOIP普及组复赛题解


    题目涉及算法:

    • 陶陶摘苹果:入门题;
    • 校门外的树:简单模拟;
    • 采药:01背包;
    • 循环:模拟、高精度。

    陶陶摘苹果

    题目链接:https://www.luogu.org/problem/P1046
    循环一遍,找到有多少数小于等于陶陶的身高+椅子的高度的即可。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    int a[10], n, cnt, tt;
    int main() {
        for (int i = 0; i < 10; i ++) cin >> a[i];
        cin >> tt;
        for (int i = 0; i < 10; i ++)
            if (a[i] <= tt + 30) cnt ++;
        cout << cnt << endl;
        return 0;
    }
    

    校门外的树

    题目链接:https://www.luogu.org/problem/P1047
    这道题目可以暴力开for循环也没有问题,但是有 (O(n)) 的算法,那就是点标记,也就是开一个数组 (c[]),对每一个区间范围 ([L,R])(c[L]++):表示从 (L) 开始有一段树开始砍了,(c[R+1]--):表示从 (R+1) 开始有一段树开始没有被砍了。
    然后开一个变量 (tmp) ,从左到右遍历过去,每次 (tmp += cnt[i]) ,如果 (tmp gt 0) ,说明 (i) 被砍掉了,不然 (i) 就没有被砍掉。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 10010;
    int n, m, l, r, cnt[maxn], tmp, ans;
    int main() {
        cin >> n >> m;
        while (m --) {
            cin >> l >> r;
            cnt[l] ++;
            cnt[r+1] --;
        }
        for (int i = 0; i <= n; i ++) {
            tmp += cnt[i];
            ans += !tmp;
        }
        cout << ans << endl;
        return 0;
    }
    

    采药

    题目链接:https://www.luogu.org/problem/P1048
    这道题目就是一道裸的01背包问题。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1010;
    int V, n, c, w, f[maxn];
    int main() {
        cin >> V >> n;
        while (n --) {
            cin >> c >> w;
            for (int i = V; i >= c; i --)
                f[i] = max(f[i], f[i-c] + w);
        }
        cout << f[V] << endl;
        return 0;
    }
    

    循环

    题目链接:https://www.luogu.org/problem/P1050
    这道题目是一道很繁琐的高精度模拟。
    题解来自:https://www.luogu.org/blog/user277/solution-p1050

    首先,我们看数据范围10^100,就知道数据有多阴险了(一股寒意袭来)~(≧▽≦)/  
    然而真正需要计算的部分就是后k位了,我们可以从尾来分析→既后1位,后2位,后3位,后4位……后k位,递推去找  
    假使输入数据位198123 4  
    ①截取后4位8123,只需对8123做处理(输入时需注意,首先输入一个字符串,分割后存入数组)  
    ②首先取最后一位3,寻找循环节(此时,用布尔数组判断是否存在循环,若不存在,直接输出-1)  
    3,9,7,1,*3,循环长度为4  
    ③此时,取后两位23:(23^4) mod 100=41 此时,23需每次乘以41,可保证最后一位不变  
     23*41^n的循环节为43 63 83 03 23 循环节长度为5,此时,循环总长度位4*5=20  
    ④通第3步操作,取后三位123:(123^20) mod 1000=201  
    123*201^n的循环节为723 323 923 523 123 循环节长度为5,此时总长度位20*5=100
    ⑤还是一样,取后四位8123:(8123^100) mod 10000=6001
    8123*6001^n的循环节位6123 4123 2123 0123 8123 循环节长度为5,此时总长度位100*5=500
    答案就出来了
    做题时需注意高精的运用和字符串处理
    还需注意,每次的(n^m) mod 10^a的结果需要代到下一次中,否则会超时!(计算时,须整个后k位都要乘)
    

    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 220;
    string s, t;
    bool vis[10];
    int k;
    string delta = "1";
    int tmp_a[maxn], tmp_b[maxn], tmp_c[maxn];
    string multi(string s1, string s2, int len) {
        int len1 = min( (int) s1.length(), len), len2 = min( (int) s2.length(), len);
        for (int i = 0; i < len1; i ++) tmp_a[i] = s1[len1-1-i] - '0';
        for (int i = 0; i < len2; i ++) tmp_b[i] = s2[len2-1-i] - '0';
        for (int i = 0; i < len; i ++) tmp_c[i] = 0;
        for (int i = 0; i < len1; i ++)
            for (int j = 0; j < len2; j ++)
                tmp_c[i+j] += tmp_a[i] * tmp_b[j];
        for (int i = 0; i < len; i ++) {
            tmp_c[i+1] += tmp_c[i] / 10;
            tmp_c[i] %= 10;
        }
        string res = "";
        for (int i = len-1; i >= 0; i --) {
            char c = '0' + tmp_c[i];
            res += c;
        }
        return res;
    }
    int tmp_d[maxn];
    bool my_check(int n) {
        return n > 1 || n == 1 && tmp_d[0] > 1;
    }
    void my_divide2(int &n) {
        for (int i = n-1; i >= 0; i --) {
            if (tmp_d[i] % 2 && i > 0) tmp_d[i-1] += 10;
            tmp_d[i] /= 2;
        }
        while (n > 0 && tmp_d[n-1] == 0) n --;
    }
    string quick_mi(string s, string t, int len) {
        string tt = "1";
        memset(tmp_d, 0, sizeof(tmp_d));
        int n = t.length();
        while (n > 0 && tmp_d[n-1]) n --;
        for (int i = 0; i < n; i ++) tmp_d[i] = t[n-1-i] - '0';
        while (my_check(n)) {
            if (tmp_d[0] % 2) tt = multi(tt, s, len);
            s = multi(s, s, len);
            my_divide2(n);
        }
        return multi(s, tt, len);
    }
    
    string multi2(string s, int a) {
        int len = s.length();
        for (int i = 0; i < len; i ++) tmp_a[i] = s[len-1-i] - '0';
        memset(tmp_b, 0, sizeof(tmp_b));
        for (int i = 0; i < len; i ++) {
            tmp_b[i] += tmp_a[i] * a;
            tmp_b[i+1] += tmp_b[i] / 10;
            tmp_b[i] %= 10;
        }
        int i = maxn-1;
        while (!tmp_b[i] && i > 0) i --;
        string res = "";
        while (i >= 0) {
            char c = '0' + tmp_b[i--];
            res += c;
        }
        return res;
    }
    int main() {
        cin >> s >> k;
        if (s.length() < k) {
            for (int i = k-s.length(); i > 0; i --)
                s = "0" + s;
        }
        for (int len = 1; len <= k; len ++) {
            t = s.substr(s.length()-len, len);
            memset(vis, 0, sizeof(vis));
            string tmp_s = t;
            int i;
            string delta_s = quick_mi(t, delta, len);
            for (i = 1; ; i ++) {
                tmp_s = multi(tmp_s, delta_s, len);
                if (tmp_s[0] == t[0]) break;
                else if (vis[ tmp_s[0] - '0' ]) {
                    cout << -1 << endl;
                    return 0;
                }
                else vis[ tmp_s[0] - '0' ] = true;
            }
            delta = multi2(delta, i);
    
        }
        cout << delta << endl;
        return 0;
    }
    

    作者:zifeiy

  • 相关阅读:
    OpenCV--图像特征(harris角点检测)
    pycharm处理命令行参数
    OpenCV--文档扫描OCR识别
    OpenCV--信用卡数字识别
    OpenCV--傅里叶变换
    OpenCV--直方图
    OpenCV--模板匹配
    OpenCV--图像轮廓
    OpenCV--图像金字塔
    51Nod-1288 汽油补给 ST表 贪心 模拟
  • 原文地址:https://www.cnblogs.com/codedecision/p/11717578.html
Copyright © 2020-2023  润新知