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\n", 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 \to 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 \to +\infty} \frac{1}{n} \sum_{i=1}^{n}f_i(x)\)
問是否所有\(x\)的權利都相同 (\(1 <= x <= n\))

  • 思路

題意其實看懂就知道當\(n \to +\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 \to 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\n", ans);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM