• ICPC 2018 Nanjing Regional


    A. Adrien and Austin

    大意:

    一共n个数,每次可以取至少1个至多k个连续的数,先手胜输出Adrien,后手胜输出Austin

    思路:

    当k=1时,直接根据n的奇偶性判断即可

    当k大于等于2时,先手总可以先取中间的1个或者2个,使得两边剩下的数量一样多,这样后手怎么选我就选和他对称的即可,这样先手必胜

    注意当n=0时先手必败的特判即可

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    typedef long long LL;
    int n, k;
    int main() {
        cin >> n >> k;
        if (n == 0) {
            cout << "Austin" << endl;
            return 0;
        }
        if (k == 1) {
            if (n % 2 == 0)
                cout << "Austin" << endl;
            else
                cout << "Adrien" << endl;
        } else {
            cout << "Adrien" << endl;
        }
        return 0;
    }
    

    D. Country Meow

    大意:给出空间上的n个点,求出一个点的位置,使得到这个点距离最远的点的距离最小

    思路:最小球覆盖问题, 和平面上的做法类似,直接套板子即可

    #include <bits/stdc++.h>
    using namespace std;
    
    int const N = 100 + 5;
    const double inf = 2e7;
    double ans = inf;
    int n;
    struct node {
        double x, y, z;
    } a[N];
    
    double getd(node a, node b) {
        double dx = a.x - b.x;
        double dy = a.y - b.y;
        double dz = a.z - b.z;
        return sqrt(dx * dx + dy * dy + dz * dz);
    }
    
    double getsum(node x) {  // f函数
        double re = 0;
        for (int i = 0; i < n; i++) {
            re = max(re, getd(x, a[i]));
        }
        ans = min(ans, re);
        return re;
    }
    
    double rand(double l, double r) {  //计算一个l到r的随机值
        return (double)rand() / RAND_MAX * (r - l) + l;
    }
    
    void sa() {
        node p{rand(-1e5, 1e5), rand(-1e5, 1e5), rand(-1e5, 1e5)};
        for (double t = 2e5; t > 1e-4; t *= 0.99) {
            node np{rand(p.x - t, p.x + t),
                   rand(p.y - t, p.y + t),rand(p.z - t, p.z + t)};  //随机一个新的点
            double dt = getsum(np) - getsum(p);        //计算能量差
            if (exp(-dt / t) >
                rand(0, 1)) {  //如果是求最大值,则exp(dt / t) > rand(0, 1)
                p = np;
            }
        }
    }
    
    int main() {
        cin >> n;
        srand((unsigned)time(NULL));
        for (int i = 0; i < n; ++i) {
            cin >> a[i].x >> a[i].y >> a[i].z;
        }
        //for (int i = 0; i < 100; ++i) sa();
        while ((double)clock() / CLOCKS_PER_SEC < 0.8) sa();
        printf("%.5lf
    ", ans);
    }
    

    G. Pyramid

    大意:

    求出n层三角形中,三角形的数量:

    图片.png

    思路:

    打表找规律,发现数量是(frac{n*(n+1)*(n+2)*(n+3)}{24})

    直接求即可,注意需要求24的逆元

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define LL long long
    
    const LL mod = 1e9 + 7;
    
    LL powmod(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() {
        LL T;
        cin >> T;
        LL inv24 = powmod(24, mod - 2);
        while (T--) {
            LL n;
            scanf("%lld", &n);
            LL Ans = n * (n + 1) % mod;
            Ans = Ans * (n + 2) % mod;
            Ans = Ans * (n + 3) % mod;
            Ans = Ans * inv24 % mod;
            printf("%lld
    ", Ans);
        }
    }
    

    I. Magic Potion

    大意:

    n个英雄,m个怪兽,k个技能

    每个英雄有各自可以打败的怪兽,每个英雄只能打一个怪兽

    每个英雄都可以用一次技能额外击败一个怪兽

    问最多可以击败多少个怪兽

    思路:

    最大流,每个英雄入度为1,每个怪兽出度为1,然后英雄和怪兽连线,另外每个英雄有一个相应的“魔法英雄”,英雄的源点入度为n,魔法英雄的源点入度为k

    #include <bits/stdc++.h>
    
    using namespace std;
    
    int const N = 1e5 + 20, M = 2e5  + 10, INF = 1e9 + 10;
    int e[M * 2], ne[M * 2], h[N], f[M * 2], idx, k;
    int d[N], cur[N], n, m, S, T;
    
    void add(int a, int b, int c) {
        e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx++;
        e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx++;
    }
    
    // bfs找是否存在增广路
    int bfs() {
        queue<int> q;
        memset(d, -1, sizeof d);
        q.push(S);
        d[S] = 0;
        cur[S] = h[S];
        while(q.size()) {
            int t = q.front();
            q.pop();
            for (int i = cur[t]; ~i; i = ne[i]) {
                int j = e[i];
                if (d[j] != -1 || !f[i]) continue;  
                d[j] = d[t] + 1;  // 更新分层图
                cur[j] = h[j];  // 当前弧优化,cur[j]记录j点第一条可以访问的边
                if (j == T) return 1;
                q.push(j);
            }
        }
        return 0;
    }
    
    // dfs把增广路更新
    int find(int u, int limit) {
        if (u == T) return limit;
        int flow = 0;
        for (int i = cur[u]; ~i && flow < limit; i = ne[i]) {  // 当前弧优化+流量限制
            cur[u] = i;
            int j = e[i];
            if (d[j] != d[u] + 1 || !f[i]) continue;  // 必须在分层图上,防止出现环;必须有流量
            int t = find(j, min(f[i], limit - flow));  // 找到从j出去的流量
            if (!t) d[j] = -1;  // 流量为0,说明这条路不行
            f[i] -= t, f[i ^ 1] += t, flow += t;  // 更新流量
        }
        return flow;
    }
    
    int dinic() {  
        int res = 0, flow = 0;
        // 每次判断是否存在增广路(bfs),如果存在,那么把所有的增广路更新(find)
        while (bfs()) while(flow = find(S, INF)) res += flow; 
        return res;
    }
    
    int main() {
        memset(h, -1, sizeof h);
        cin >> n >> m >> k;
        S = 0, T = 2 * n + m + 1;
        for (int i = 1, t; i <= n; ++i) {
            cin >> t;
            for (int j = 1, mon; j <= t; ++j) {
                cin >> mon;
                add(i, 2 * n + mon, 1);
                add(n + i, 2 * n + mon, 1);
            }
        }
        for (int i = 1; i <= n; ++i) add(S, i, 1);
        for (int i = 1; i <= m; ++i) add(2 * n + i, T, 1);
        add(S, 2 * n + m + 2, k);
        for (int i = 1; i <= n; ++i) add(2 * n + m + 2, n + i, 1); 
        printf("%d
    ", dinic());
        return 0;
    }
    

    J. Prime Game

    大意:

    给出n个数的数组,问这个数组的所有区间的 元素的积的素因子的个数和是多少

    思路:

    分别对每个素因子考虑贡献

    对于一个素因子来说,记录其出现的位置,那么它全部的贡献可以由(n*(n+1)/2)减去每个没有出现的小区间的贡献组成

    图片.png

    如图为例,贡献可表示为(n*(n+1)/2-d_0*(d_0+1)/2-d_1*(d_1+1)/2-d_2*(d_2+1)/2-d_3*(d_3+1)/2)

    但是仅仅想出这个还不行,暴力会超时

    一个优化的方法是先将1到1e6的数全部分解质因数,然后对于输入的数,直接看它的质因子有哪些, 并标记出现的位置,计算贡献

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long LL;
    typedef pair<LL, LL> PII;
    LL const N = 1e6 + 10;
    unordered_map<LL, vector<LL>> mp;
    unordered_map<LL, LL> sum;
    vector<LL> num[N];
    LL prime[N];
    LL st[N];
    LL cnt = 0;
    
    void get_prime(LL n) {
        for (LL i = 2; i <= n; ++i) {
            if (!st[i]) {
                prime[cnt++] =
                    i;  // 如果这个数字没有被记录,那么这个数字必然为素数,记录一下
                num[i].push_back(i);
            }
            for (LL j = 0; prime[j] <= n / i; ++j) {
                st[prime[j] * i] = true;  // 筛掉pj*i这个合数
                if (i % prime[j] == 0)
                    break;  // i%pj==0,说明pj是i的最小素因子,因此i*素数的最小素因子也是pj,在i递增的时候也会被筛掉,因此不需要在这里判断
            }
        }
        for (LL i = 0; i < cnt; i++) {
            for (LL j = 1; j <= n; j++) {
                if (j * prime[i] > n) break;
                num[j * prime[i]].push_back(prime[i]);
            }
        }
    }
    
    int main() {
        get_prime(1e6);
        LL n;
        scanf("%lld", &n);
        for (LL i = 1; i <= n; i++) {
            LL x;
            scanf("%lld", &x);
            for (LL j = 0; j < num[x].size(); j++) {
                LL p = num[x][j];
                mp[p].push_back(i);
                LL d;
                if (mp[p].size() == 1)
                    d = i - 1;
                else
                    d = i - mp[p][mp[p].size() - 2] - 1;
                sum[p] += d * (d + 1) / 2;
            }
        }
        LL ans = 0;
        for (auto it = mp.begin(); it != mp.end(); it++) {
            LL d = n - (it->second)[(it->second).size() - 1];
            ans += n * (n + 1) / 2 - (sum[it->first] + d * (d + 1) / 2);
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    K. Kangaroo Puzzle

    大意:

    给出一个地图,每个1上面都有一个袋鼠,每个0都是墙,现在要求给出一个不长于5e4的字符串,全体袋鼠按照这个字符串的方向移动,不会穿过墙,问能否最后汇聚到一个点上

    思路:

    看题解才知道可以利用随机化莽过去....因为地图很小,而字符串很长,所以随机移动有很大的几率使得袋鼠汇聚到一点

    不过也是要看运气的,a数组一开始写的LRUD就没过,改成ULRD就过了.....真的玄学

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int N = 1e6 + 5;
    typedef long long LL;
    char a[4] = {'U', 'L', 'R', 'D'};
    int main() {
        srand(time(0));
        int n, m;
        cin >> n >> m;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                char x;
                cin >> x;
            }
        }
        for (int i = 0; i < 50000; i++)
            cout << a[int(double(rand()) / RAND_MAX * 3.0 + 0.5)];
        cout << endl;
        return 0;
    }
    
  • 相关阅读:
    SQL Serever学习16——索引,触发器,数据库维护
    微信WeUI基础
    SQL Serever学习15——进阶
    SQL Serever学习14——存储过程和触发器
    微信WeUI入门2
    微信WeUI入门
    数据库—索引
    数据库—四种存储引擎
    视图
    事务
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/14404395.html
Copyright © 2020-2023  润新知