zoukankan      html  css  js  c++  java
  • 2021“MINIEYE杯”中国大学生算法设计超级联赛(7)

    2021“MINIEYE杯”中国大学生算法设计超级联赛(7)

    1003. Fall with Trees

    • 题意

    一棵完全二叉树,且子节点和父节点高度一定,同一深度的子节点y坐标相同,且每两个子节点的距离相同, 求整棵树连起来的总面积。

    • 思路

    建议推公式求,暴力调精度会出大问题(呜呜呜)。
    首先(S_i =h * frac{w_k + w_{k + 1} }{2})
    然后每个(w_1 = fabs(x_2 - x_1), h = y_1 - y_0),(w_i = 2 * w_1 - 2^{1-i})
    然后推出公式展开求一个等比前(n)项就可以了。
    (ANS = sum_{i=1}^{k-1} S_i = w_1 * h / 2.0 * (4 * (k - 1) - 3 * (2 - 2^{k-2}))

    code :

    void solve(){
        db x0,x1,x2,y0,y1,y2;
        int k;
        sc("%d", &k);
        scanf("%lf%lf%lf%lf%lf%lf", &x0, &y0, &x1, &y1, &x2, &y2);
        db h = fabs(y1 - y0);
        db w = fabs(x2 - x1);
        db ans = w * h / 2.0 * (4.0 * (k - 1) - 3.0 * (2.0 - pow(2,2 - k)));
        pr("%.3lf
    ", ans);
    }
    
    
    • 题意

    给你一个(n),(m),有(2n)个筐,你可以从(2x - 1)的筐中拿(k*x)个球(k为非负整数),也可以从(2x)的框中最多拿(x)个球, 问如果要(m)个球,有多少种拿法。

    • 思路
    1 2 3 4 5 6
    (+infty) 0 ~ 1 2k 0 ~ 2 3k 0 ~ 3
    我们可以发现,第一个为正无穷,然后其实将(2 and 3)组合,也可以得到正无穷。
    最后我们就得到(n)个无穷筐和一个从(0 o n)的筐。
    然后就枚举最后那个筐选中的个数,然后在剩下的在前面的无穷筐中选即可
    然后就是隔板法取即可,在((m - i))个数中,用(n - 1)个隔板划分成(n)个区域
    计算(sum_{i = 0}^nC_{m - i + n - 1}^{n-1})
    由公式(sum_{i=0}^nC_{k+i}^k = C_{n + k + 1}^{k + 1})
    (ans = C_{n + m}^n - C_{m - 1}^n)

    code :

    ll fact[N], infact[N];
    
    void init() {
    	fact[0] = infact[0] = 1;
        for (int i = 1 ; i < N; ++i) {
            fact[i] = fact[i - 1] * i % MOD;
            infact[i] = infact[i - 1] * pow_mod(i, MOD - 2) % MOD;
        }
    }
    
    ll C(ll a,ll b) {
    	if(a<0||b<0||a<b) return 0;
    	return fact[a] * infact[a - b] % MOD * infact[b] % MOD;
    }
    ll qmi(int a, int k, int p) {
        LL res = 1;
        while (k) {
            if (k & 1) res = (LL)res * a % p;
            k >>= 1;
            a = (LL)a * a % p;
        }
        return res;
    }
    
    void solve(){
        int n,m;
        cin >> n >> m;
        ll ans = C(n + m,n) - C(m - 1,n) + 3 * mod;
        cout << ans % mod << endl;
    }
    
    • 题意

    一个人,往任意方向扔一颗速度为(v),爆炸范围为(r)的手榴弹,并且将在(t)秒后爆炸,问不炸死自己的概率。

    • 思路

    画图形,推一遍物理公式即可

    code : (略)(过于难看)

    • 题意

    定义一个函数(f(x)), 且(x)(f(x))都属于([1,n]) , 且(f_n(x) = f(f_{n-1}(x)) and f_1(x) = f(x))
    定义(x)的权力为
    (g(x) = lim_{n o +infty} frac{1}{n} sum_{i=1}^{n}f_i(x))
    问是否所有(x)的权利都相同 ((1 <= x <= n))

    • 思路

    题意其实看懂就知道当(n o +infty)时,非环点的权值可以忽略因为一定要(* frac{1}{+infty}), 然后其实就是权值就是一堆环内一直跳的点,那么拓扑排序清边,然后一直找环即可,判断是否每个环的点权平均值都相同即可。

    code:

    int a[N], ru[N];
    int q[N];
    void solve(){
        int n;
        cin >> n;
        memset(ru, 0, sizeof ru);
        fep(i,1,n) {
            cin >> a[i];
            ru[a[i]] ++;
        } 
        int hh = 0,tt = -1;
        fep(i,1,n) {
            if(ru[i] == 0) q[++ tt] = i; 
        }
        while(hh <= tt) {
            int t = q[hh ++];
            ru[a[t]] --;
            if(ru[a[t]] == 0) {
                q[++ tt] = a[t];
            }
        }
        ll va = -1, vb = -1;
        for(int i = 1;i <= n;i ++) {
            ll sa = 0,sb = 0;
            if(ru[i]) {
                int j = i;
                while(ru[j]) {
                    ru[j] = 0; // 每个点只会出现在一个环上
                    sa ++;
                    sb += j;
                    j = a[j];
                }
                if(va == -1) {
                    va = sa, vb = sb;
                }else {
                    if(va * sb != vb * sa) {
                        cout << "NO" << endl;
                        return;
                    }
                }
            }
        }
        cout << "YES" << endl;
    }
    

    1008. Smzzl with Greedy Snake

    • 题意

    贪吃蛇,可以直走 = (f),顺时针旋转(90^{circ}) = (c), 逆时针(90^{circ}) = (u), 每次吃完一个才会出现下一个,问你如何用最少的行动吃完。

    • 思路

    模拟0.0

    code:

    void solve(){
        int x,y,d;
        cin >> x >> y >> d; // 0 - y+, 1- x+, 2- y-,3 x-
        int m;
        cin >> m;
        string str = "";
        fep(i,1,m) {
            int a,b;
            cin >> a >> b;
            int flag = -1; // 0 - 左上, 1- 左下,2- 右上, 3- 右下
            // 先判断直走
            if(a > x) flag += 2;
            if(b < y) flag += 2;
            else flag ++;
            
            if(flag == 0) {
                if(d == 1) d = 0, str += "u";
                if(d == 2) d = 3, str += "c";
                if(d == 0) {
                    while(y < b) str += "f", y ++;
                    str += "u";
                    while(x > a) str += "f", x --;
                    d = 3;
                }
                else if(d == 3) {
                    while(x > a) str += "f", x --;
                    str += "c";
                    while(y < b) str += "f", y ++;
                    d = 0;
                }
            }else
            if(flag == 1) {
                if(d == 0) d = 3, str += "u";
                if(d == 1) d = 2, str += "c";
                if(d == 2) {
                    while(y > b) str += "f", y --;
                    str += "c";
                    while(x > a) str += "f", x --;
                    d = 3;
                }
                else if(d == 3) {
                    while(x > a) str += "f", x --;
                    str += "u";
                    while(y > b) str += "f", y --;
                    d = 2;
                }
            }else
            if(flag == 2) {
                if(d == 2) d = 1, str += "u";
                if(d == 3) d = 0, str += "c";
                if(d == 0) {
                    while(y < b) str += "f", y ++;
                    str += "c";
                    while(x < a) str += "f", x ++;
                    d = 1;
                }
                else if(d == 1) {
                    while(x < a) str += "f", x ++;
                    str += "u";
                    while(y < b) str += "f", y ++;
                    d = 0;
                }
            }else {
                if(d == 3) d = 2, str += "u";
                if(d == 0) d = 1, str += "c";
                if(d == 1) {
                    while(x < a) str += "f", x ++;
                    str += "c";
                    while(y > b) str += "f", y --;
                    d = 2;
                }
                else if(d == 2) {
                    while(y > b) str += "f", y --;
                    str += "u";
                    while(x < a) str += "f", x ++;
                    d = 1;
                }
            }
        }
        cout << str << endl;
    }
    

    1010. Smzzl with Tropical Taste

    • 题意

    一个泳池,一个人每秒忘泳池里倒(q)升的冰红茶,一个人每秒从泳池里喝(p)升的冰红茶(手动滑稽),问对任意(G)升冰红茶,都存在一个时间(T),在男孩和了(t)秒后的,喝了大于(G)升的冰红茶。

    • 思路

    只有当倒的冰红茶小于喝的时候才会有限制,其他时候都是无限制的。

    code :

    const double eps = 1e-6;
    void solve(){
        db n,m;
        cin >> n >> m;
        if(n - m > eps) {
            cout << "ENJ0Y YOURS3LF!" << endl;
        }else {
            cout << "N0 M0R3 BL4CK 1CE TEA!" << endl;
        }
    }
    

    1012. Yiwen with Sqc

    • 题意

    给一个字符串,(sqc(s,l,r,c))表示字符串(s)中从(l o r)(c)字符出现的次数,然后求一个:

    (sum_{c=97}^{122}sum_{i=1}^{n}sum_{j=i}^{n} sqc(s,i,j,c)^2 mod 998244353)

    • 思路

    我的解法是推公式写的。。
    就比如: ababa
    1: a a贡献 a : 1
    2: b ab贡献a: 1,b : 1 + 1
    3: a aba贡献a: 4 + 1 + 1, b : 1 + 1
    4: b abab贡献a:4 + 1 + 1, b : 4 + 4 + 1 + 1
    5: a ababa贡献a: 9 + 4 + 4 + 1 + 1, b : 4 + 4 + 1 + 1.
    然后发现其他字符变动对自己的贡献是没有影响的。
    之后就靠脑子想了,
    (a)中的贡献为(a_1 + a_3 + a_5),
    (a_1)进来时为1,
    (a_3)进来后即为((a_1=1 + 1)^2 + 1 + k_i)(k_i)表示有多少次没有出现当前字母了,表示(k_i)(+1)
    然后(a_5)进来,就是((a_1=1 + 1 + 1)^2) + (a_2=1 + 1)^2 + (a_2=1 + 1)^2 + 1 + k_i = 9 + 4 + 4 + 1 + 1), 然后计算公式(O(26n))即可求解,没有卡常。。

    code:

    char str[N];
    int f[N][27];
    int s[N][27];
    int cnt[27], k[27]; // cnt表示当前某个字符贡献了多少次如+4+1+1,贡献为6,cnt为3, k表示已经多久没出现当前字符
    
    void solve(){
        sc("%s", str + 1);
        int n = strlen(str + 1);
        for(int i = 1;i <= n;i ++) {
            fep(j,1,26) f[i][j] = f[i - 1][j], s[i][j] = s[i - 1][j], k[j] ++;
            if(!cnt[str[i] - 'a' + 1]){
                int now = str[i] - 'a' + 1;
                f[i][now] = i;
                s[i][now] += cnt[now] + k[now];
                cnt[now] += k[now];
                k[now] = 0;
            }
            else {
                int now = str[i] - 'a' + 1;
                f[i][now] += cnt[now] + k[now] + 2 * s[i][now] % mod;
                f[i][now] %= mod;
                cnt[now] += k[now];
                s[i][now] += cnt[now];
                k[now] = 0;
            }
        }
        int ans = 0;
        for(int i = 1;i <= n;i ++) {
            fep(j,1,26){
                ans += f[i][j];
                ans %= mod;
            }
        }
        fep(i,1,26) k[i] = cnt[i] = 0;
        pr("%lld
    ", ans);
    }
    
  • 相关阅读:
    猜拳游戏
    python2.7安装paramiko模板(windows)
    python socket编程(初级)
    Python2.7怎么安装MySQLdb模板(Windows32)
    Python的用户交互模式
    一个java程序员自学IOS开发之路(三)
    一个java程序员自学IOS开发之路(二)
    一个java程序员自学IOS开发之路(一)
    win 7 取得最高权限
    Multiset ------ 多重集合
  • 原文地址:https://www.cnblogs.com/darker-wxl/p/15127231.html
Copyright © 2011-2022 走看看