zoukankan      html  css  js  c++  java
  • 某比赛的某些题目

    这里我只写一些认为应该写报告的题目。。。像那种5分钟敲出代码的题就不写了。感谢@xianbin5组织这场比赛,Orz


    题目1:给一些数据,建议一颗排序二叉树。然后找到某个节点的祖父节点(父节点的父节点)n <= 50000;

    题解:描述很简单,而且可以很简单的敲出来。但是注意数据量。。。所以这里要用到特殊的东西。

    一个颗很神奇的数:笛卡尔树

    笛卡尔树跟treap结构完全一样。不过区别在于treap的heap部分是随机取的,笛卡尔树的val是之前确定好的。

    笛卡尔树的构造过程:先对数据的key值进行从小到大排序,然后一次插入笛卡尔树。过程跟treap一样,不过可以发现,因为数据是排好序的,所以每次插入的节点肯定是在原树最右侧的节点开始找的。这样就能实现最优甚至接近O(n)的时间建树。。。。

    View Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <ctime>
    #include <queue>
    #include <map>
    #include <sstream>
    #include <stack>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   x < y ? x : y
    #define Max(x, y)   x < y ? y : x
    #define E(x)    (1 << (x))
    
    const int eps = 1e-6;
    const int inf = ~0u>>2;;
    typedef long long LL;
    
    using namespace std;
    
    const int N = 50010;
    
    map<int, int> mp;
    
    struct node {
        int key, val;
        int ls, rs, pre;
    } p[N];
    
    bool operator < (const node& a, const node& b) {
        return a.key < b.key;
    }
    
    void build_tree(int n) {
        int i, k = 1;
        p[0].rs  = 1;
    
        for(i = 2; i <= n; ++i) {
            while(p[k].val > p[i].val)  k = p[k].pre;
            p[i].ls = p[k].rs;
            p[p[k].rs].pre = i;
            p[k].rs = i;
            p[i].pre = k;
            k = i;
        }
    
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int n, m, i, x;
        while(~scanf("%d%d", &n, &m)) {
            mp.clear();
            for(i = 0; i <= n; ++i) {
                p[i].pre = 0; p[i].val = 0;
                p[i].ls = p[i].rs = 0;
            }
            for(i = 1; i <= n; ++i) {
                scanf("%d", &p[i].key);
                p[i].val = i;
                p[i].pre = 0;
            }
            sort(p + 1, p + n + 1);
            for(i = 1; i <= n; ++i) {
                mp[p[i].key] = i;
            }
            build_tree(n);
    
            while(m--) {
                scanf("%d", &x);
                x = mp[x];
                if(p[x].pre == 0)  {puts("-1"); continue;}
                x = p[x].pre;
                if(p[x].pre == 0)  {puts("-1"); continue;}
                x = p[x].pre;
                printf("%d\n", p[x].key);
            }
        }
        return 0;
    }

    题目2:给出由'0','1','2','3','?'组成的串A,B,C。其中'?'表示该位可能是0,1,2,3,若有A+B=C,则称[A,B,C]是这三个字符串的一组解,给出A,B,C,求解的个数。

     题解:这题很容易想到模拟。不过我写的模拟没过。。。还有更好的方法。。。dp

    dp[i][0]表示第i位没有进位的情况数。

    dp[i][1]表示第i位有进位时的情况数。

    然后对每一位进行模拟加法

    View Code
    string a, b, c;
    
    int dp[20][2];
    
    int solve() {
        CL(dp, 0);
        reverse(a.begin(), a.end());
        reverse(b.begin(), b.end());
        reverse(c.begin(), c.end());
    
        int i, j, k, l, cy, m = 0;
        int sa, ea, sb, eb, sc, ec;
    
        dp[0][0] = 1; dp[0][1] = 0;
    
        for(i = 0; i < a.length() || i < b.length() || i < c.length(); ++i) {
            sa = sb = sc = 0; ++m;
            if(i < a.length())  ea = 3;
            else    ea = 0;
            if(i < b.length())  eb = 3;
            else    eb = 0;
            if(i < c.length())  ec = 3;
            else    ec = 0;
    
            if(a[i] != '?' && i < a.length()) sa = ea = a[i] - '0';
            if(b[i] != '?' && i < b.length()) sb = eb = b[i] - '0';
            if(c[i] != '?' && i < c.length()) sc = ec = c[i] - '0';
    
            for(j = sa; j <= ea; ++j) {
                for(k = sb; k <= eb; ++k) {
                    for(l = sc; l <= ec; ++l) {
                        for(cy = 0; cy < 2; ++cy) {
                            if(l == (j + k + cy)%4) {
                                dp[i+1][(j + k + cy)/4] += dp[i][cy];
                            }
                        }
                    }
                }
            }
        }
        return dp[m][0];
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        while(cin >> a >> b >> c) {
            int ans = solve();
            cout << ans << endl;
        }
        return 0;
    }

    题目3:给一个数n,找出[1, n]中包含因子个数最多的数,如果这个数有多个,找最小的那一个。

    题解:对n分解质因子 n = p1^k1 * p2^k2 * ..... 所以n的因子数为 (k1 + 1)*(k2 + 1) *(k3 + 1) * ....

    可以反过来,不去分解质因子,而是用这些素数去组合,枚举出1-n中所有数有多少个质因子

    其实前边这些已经可以解决这个问题了,不过还有一个规律进行优化。

    12 = 3 * 2^2 18 = 3^2 * 2;

    12 < 18,可以在枚举时进行一个优化,使得枚举到的数字中2的指数不小于3的指数,3的指数不小于5的指数……这样我们就能够得到质因数分解“模式”相同的最小数(证明略)。再对于每一个得到的数进行比较和记录。

    View Code
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <string>
    #include <set>
    #include <ctime>
    #include <queue>
    #include <map>
    #include <sstream>
    #include <stack>
    
    #define CL(arr, val)    memset(arr, val, sizeof(arr))
    #define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
    #define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
    #define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
    #define L(x)    (x) << 1
    #define R(x)    (x) << 1 | 1
    #define MID(l, r)   (l + r) >> 1
    #define Min(x, y)   x < y ? x : y
    #define Max(x, y)   x < y ? y : x
    #define E(x)    (1 << (x))
    
    const int eps = 1e-6;
    const int inf = ~0u>>2;;
    typedef long long LL;
    
    using namespace std;
    
    int prime[12] = {2,3,5,7,11,13,17,19,23,29,31,37};
    int _max, num, n;
    
    void solve(int m, int t, int f, int limt) {
        int j, l;
        LL  i, p;
        if(t > _max || (t == _max && m < num))    {num = m; _max = t;}
        j = 0; l = 1; i = m;
        while(i <= n && j < limt) {
            j++; l++; i = i*prime[f]; p = t*l;
            if(i <= n)  solve(i, p, f + 1, j);
        }
    }
    
    int main() {
        //freopen("data.in", "r", stdin);
    
        int t;
        scanf("%d", &t);
        while(t--) {
            scanf("%d", &n);
            _max = 1; num = 1;
            if(n == 1)  puts("1");
            else {
                solve(1, 1, 0, 30);
                printf("%d\n", num);
            }
        }
        return 0;
    }
  • 相关阅读:
    安卓任意两个或多个Fragment之间的交互与刷新界面
    内存溢出和内存泄漏
    求直方图围成的最大矩形面积
    判断一个字符串是否是由另2个字符串交错组成的
    矩阵的旋转
    求滑动窗口的最大值
    面向过程和面向对象的区别
    关于丑数
    求连续子数组的最大和
    多数投票算法(Majority Vote Algorithm)
  • 原文地址:https://www.cnblogs.com/vongang/p/2603414.html
Copyright © 2011-2022 走看看