2020 Multi-University Training Contest 5

Tetrahedron

1 h 2 = 1 a 2 + 1 b 2 + 1 c 2 \cfrac{1}{h^2}=\cfrac{1}{a^2}+\cfrac{1}{b^2}+\cfrac{1}{c^2} h21=a21+b21+c21

E ( x + y ) = E ( x ) + E ( y ) E(x+y)=E(x)+E(y) E(x+y)=E(x)+E(y)

// 百思不得其解 赛中3秒过了 赛后T cin改成scanf后4秒过了 hdu这是什么机制???
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = 6e6 + 10;
int n;

ll qpow(ll a, ll b) {
    a %= mod;
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

ll f[N], sum[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    for (int i = 1, lim = 6e6; i <= lim; i++) {
        f[i] = qpow(1ll * i * i, mod - 2);
        sum[i] = (sum[i - 1] + f[i]) % mod;
    }

    int T;
    cin >> T;
    while (T--) {
        cin >> n;
        ll a = (qpow(n, mod - 2) * 3) % mod;
        cout << ((a * sum[n]) % mod) << endl;
    }
    return 0;
}

Funny String

Boring Game

官方题解
在这里插入图片描述
在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
vector<int> v[N];
int a[N];
int n, m, k;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    
    int T;
    cin >> T;
    for (int cs = 1; cs <= T; cs++) {
  
        cin >> n >> k;
        int lim = 2 * n * (1 << k);
        m = (1 << k);
        for (int i = 1; i <= m; i++) {
            v[i].clear();
        }
        for (int i = 1; i <= lim; i++) {
            cin >> a[i];
            v[m].push_back(a[i]);
        }
        reverse(v[m].begin(), v[m].end());
        for (int t = 0; t < k; t++) {
            for (int i = m - (1 << t) + 1, j = i - 1; i <= m; i++, j--) {
                int mid = v[i].size() / 2;
                for (int l = 0; l < mid; l++) {
                    v[j].push_back(v[i].back());
                    v[i].pop_back();
                }
            }
        }

        for (int i = 2 * n - 1; i >= 0; i--) {
            for (int j = 1; j <= m; j++) {
                cout << v[j][i] << (j == m && i == 0 ? "\n" : " ");
            }
        }
    }
    return 0;
}

Expression
Array Repairing
Alice and Bob
Tree
Set2


Paperfolding

经画图 和撕了N张纸 后发现,左右对折、上下对折之间的顺序没有任何关系,

假设左右对折了 x x x 次,上下对折了 y y y 次,最后横竖裁开,纸片个数 = ( 2 x + 1 ) ( 2 y + 1 ) =(2^x+1)(2^y+1) =(2x+1)(2y+1)

E ( x ) = ∑ x × p ( x ) = ∑ x = 0 n C n x ( 2 x + 1 ) ( 2 n − x + 1 ) 2 n E(x)=\sum x\times p(x)=\sum^n_{x=0} \cfrac{C^x_n(2^x+1)(2^{n-x}+1)}{2^n} E(x)=x×p(x)=x=0n2nCnx(2x+1)(2nx+1)

其中分子部分
∑ x = 0 n C n x ( 2 x + 1 ) ( 2 n − x + 1 ) = ∑ x = 0 n C n x ( 2 n + 2 x + 2 n − x + 1 ) = 2 n ∑ x = 0 n C n x + ( ∑ x = 0 n C n x 2 x + ∑ x = 0 n C n x 2 n − x ) + ∑ x = 0 n C n x \sum^n_{x=0}C^x_n(2^x+1)(2^{n-x}+1)\\=\sum^n_{x=0}C^x_n(2^n+2^x+2^{n-x}+1)\\=2^n\sum^n_{x=0}C^x_n+(\sum^n_{x=0} C^x_n2^x+\sum^n_{x=0} C^x_n2^{n-x})+\sum^n_{x=0} C^x_n x=0nCnx(2x+1)(2nx+1)=x=0nCnx(2n+2x+2nx+1)=2nx=0nCnx+(x=0nCnx2x+x=0nCnx2nx)+x=0nCnx

观察发现
∑ x = 0 n C n x 2 x = ∑ x = 0 n C n x 2 x × 1 n − x = ( 2 + 1 ) n = 3 n \sum^n_{x=0} C^x_n2^x=\sum^n_{x=0} C^x_n2^x\times 1^{n-x}=(2+1)^n=3^n x=0nCnx2x=x=0nCnx2x×1nx=(2+1)n=3n

对,就是化成二项式,就是下面这个↓

( a + b ) n = ∑ k = 0 n C n k a k b n − k (a+b)^n=\sum^n_{k=0}C^k_na^kb^{n-k} (a+b)n=k=0nCnkakbnk
a = 1 a=1 a=1 b = 1 b=1 b=1 时,

( 1 + 1 ) n = ∑ k = 0 n C n k 1 k 1 n − k = ∑ k = 0 n C n k = 2 n (1+1)^n=\sum^n_{k=0}C^k_n1^k1^{n-k}=\sum^n_{k=0}C^k_n=2^n (1+1)n=k=0nCnk1k1nk=k=0nCnk=2n

然后回到本题,同理可得
∑ x = 0 n C n x 2 n − x = ∑ x = 0 n C n x 2 n − x × 1 x = ( 1 + 2 ) n = 3 n \sum^n_{x=0} C^x_n2^{n-x}=\sum^n_{x=0} C^x_n2^{n-x}\times 1^{x}=(1+2)^n=3^n x=0nCnx2nx=x=0nCnx2nx×1x=(1+2)n=3n

因此化简原来的公式可以得出

E ( x ) = 2 n + 1 + 2 × 3 n 2 n E(x)= 2^n+1+\cfrac{2\times3^n}{2^n} E(x)=2n+1+2n2×3n

记个和这题没什么关系的笔记:

裁纸数个数的时候发现,如果只有左右对折 or 上下对折时,记 a x a_x ax 为对折了 x x x 次后纸片的个数

有如下数列:
a 1 = 6 a_1=6 a1=6 a 2 = 10 a_2=10 a2=10 a 3 = 18 a_3=18 a3=18 a 4 = 34 a_4=34 a4=34

a 2 − a 1 = 4 a_2-a_1=4 a2a1=4 a 3 − a 2 = 8 a_3-a_2=8 a3a2=8 a 4 − a 3 = 16 a_4-a_3=16 a4a3=16

求像这种公差为等比数列的通项公式,一般分为如下步骤:

以上面的数列为例,记
a n + 1 = a n + 2 n + 1 a_{n+1}=a_n+2^{n+1} an+1=an+2n+1

然后让等式左右两边都减去同一个数 x x x

a n + 1 − x = a n + 2 n + 1 − x a_{n+1}-x=a_n+2^{n+1}-x an+1x=an+2n+1x

这个数是自己构造的,构造出来的目的是使等式左右两边相似,这里令 x = 2 n + 2 x=2^{n+2} x=2n+2

a n + 1 − 2 n + 2 = a n + 2 n + 1 − 2 n + 2 = a n + 2 n + 1 − 2 × 2 n + 1 = a n − 2 n + 1 a_{n+1}-2^{n+2}=a_n+2^{n+1}-2^{n+2}=a_n+2^{n+1}-2\times2^{n+1}=a_n-2^{n+1} an+12n+2=an+2n+12n+2=an+2n+12×2n+1=an2n+1

发现 a n − 2 n + 1 a_n-2^{n+1} an2n+1 是个公比 q = 1 q=1 q=1 的等比数列,

因此可以直接往前推

a n − 2 n + 1 = . . . = a 1 − 2 2 = 6 − 4 = 2 a_n-2^{n+1}=...=a_1-2^2=6-4=2 an2n+1=...=a122=64=2

a n = 2 n + 1 + 2 a_n=2^{n+1}+2 an=2n+1+2

总结:若存在 a n + 1 = a n + b k a_{n+1}=a_n+b^k an+1=an+bk,则构造通项公式 a n − b k + 1 b − 1 a_n-\cfrac{b^{k+1}}{b-1} anb1bk+1

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;

namespace MOD { // 取模运算板子
    const ll mod = 998244353;

    ll qpow(ll a, ll b) {
        a %= mod;
        ll res = 1;
        while (b) {
            if (b & 1) res = res * a % mod;
            a = a * a % mod;
            b >>= 1;
        }
        return res;
    }

    ll Mul(ll a, ll b) {
        return (a * b) % mod;
    }

    ll Sub(ll a, ll b) {
        return (a - b + mod) % mod;
    }

    ll Add(ll a, ll b) {
        return (a + b) % mod;
    }
}
using namespace MOD;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int T;
    cin >> T;
    while (T--) {
        cin >> n;
        if (n == 0) cout << 4 << endl;
        else if (n == 1) cout << 6 << endl;
        else {
            ll _2n = qpow(2, n);// 2^n
            ll _3n = qpow(3, n); // 3^n
            ll Inv_2n = qpow(_2n, mod - 2); // 1/2^n

            ll res = Add(1, Add(_2n, Mul(Mul(2, _3n), Inv_2n)));
            cout << res << endl;
        }
    }
    return 0;
}

Function
Exam


Set1

官方题解有问题,就不贴了…

c n t [ i ] cnt[i] cnt[i] 表示第 i i i 个元素被留到最后的方案数

此时,被删去的元素有前面 i − 1 i-1 i1 个 和 后面 n − i n-i ni

前面 i − 1 i-1 i1 个元素里有操作1删去的,也有操作2随机删去的,但后面 n − i n-i ni个元素一定是被操作2随机删去的,

所以当且仅当 n − i ≤ i − 1 n-i\le i-1 nii1 的时候, i i i 才有可能被留下

题目规定操作1和操作2轮流操作,所以在前面 i − 1 i-1 i1 个元素里挑选 n − i n-i ni 个,和后面 n − i n-i ni 个元素匹配,

且由于操作1每次都是删除整个集合里最小的元素,所以在前面 i − 1 i-1 i1个元素里选出来的 n − i n-i ni个元素,一定是有序的,但后面的 n − i n-i ni个元素是无序的,所以这一部分的方案数有

C i − 1 n − i × ( n − i ) ! C_{i-1}^{n-i}\times (n-i)! Ci1ni×(ni)!

再考虑前面剩下的 i − 1 − ( n − i ) = 2 i − n − 1 i-1-(n-i)=2i-n-1 i1(ni)=2in1 个元素两两配对,

我们知道如果n个元素里两两配对,会有
C n 2 × C n − 2 2 × C n − 4 2 . . . × C 2 2 C^{2}_{n}\times C^{2}_{n-2} \times C^2_{n-4}...\times C^2_2 Cn2×Cn22×Cn42...×C22 = n ( n − 1 ) 2 × ( n − 2 ) ( n − 3 ) 2 × . . . × 2 × 1 2 = n ! 2 n 2 =\cfrac{n(n-1)}{2}\times \cfrac{(n-2)(n-3)}{2} \times...\times \cfrac{2\times1}{2}=\cfrac{n!}{2^{\frac{n}{2}}} =2n(n1)×2(n2)(n3)×...×22×1=22nn!

其中两两分配的元素相同,但前后顺序不同(12|34、 34|12 这样的)有 n 2 ! \cfrac{n}{2}! 2n!

但是在前面剩下的 2 i − n − 1 2i-n-1 2in1 个元素里,

分组后每一组里的两个数显然是小数为操作1删除的,大数为操作2删除的,是固定的顺序,

且所有组先后发生的顺序也是固定的,如果有分组如 12|34,显然3、4的删除不可能能发生在1、2的删除之前

所以这一部分的方案数有
( 2 i − n − 1 ) ! 2 2 i − n − 1 2 × 1 ( 2 i − n − 1 2 ) ! \cfrac{(2i-n-1)!}{2^\frac{2i-n-1}{2}}\times \frac{1}{(\frac{2i-n-1}{2})!} 222in1(2in1)!×(22in1)!1

所以第 i i i 个元素被留到最后的方案数为
c n t [ i ] = C i − 1 n − i × ( n − i ) ! × ( 2 i − n − 1 ) ! 2 2 i − n − 1 2 × 1 ( 2 i − n − 1 2 ) ! cnt[i]=C_{i-1}^{n-i}\times (n-i)! \times \cfrac{(2i-n-1)!}{2^\frac{2i-n-1}{2}}\times \frac{1}{(\frac{2i-n-1}{2})!} cnt[i]=Ci1ni×(ni)!×222in1(2in1)!×(22in1)!1

总方案数 s u m = ∑ c n t [ i ] sum=\sum cnt[i] sum=cnt[i]

每个数被留下的概率 p [ i ] = c n t [ i ] s u m p[i]=\cfrac{cnt[i]}{sum} p[i]=sumcnt[i]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int N = 5e6 + 10;
const int M = 5e6;
int n;

ll Mul(ll a, ll b) { return (a * b) % mod; }

ll Add(ll a, ll b) { return (a + b) % mod; }

ll Sub(ll a, ll b) { return (a - b + mod) % mod; }

ll qpow(ll a, ll b) {
    a %= mod;
    ll res = 1;
    while (b) {
        if (b & 1) res = Mul(res, a);
        b >>= 1;
        a = Mul(a, a);
    }
    return res;
}

ll fac[N], inv[N];
ll inv_2[N];// 1/(2^i)

void init(int n) {
    fac[0] = inv[0] = inv_2[0] = 1;
    int inv2 = qpow(2, mod - 2);
    for (int i = 1; i <= n; ++i) {
        fac[i] = Mul(fac[i - 1], i);
        inv_2[i] = Mul(inv_2[i - 1], inv2);
        inv[i] = Mul(inv[i - 1], qpow(i, mod - 2));
    }
}

ll C(int n, int m) {
    if (n < m || m < 0)return 0;
    return Mul(Mul(fac[n], inv[m]), inv[n - m]);
}

ll cnt[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);

    init(M);
    int T;
    cin >> T;
    for (int cs = 1; cs <= T; cs++) {

        cin >> n;
        ll sum = 0;
        for (int i = 1; i <= n; i++) {
            int tmp = i * 2 - n - 1;
            if (tmp < 0) cnt[i] = 0;
            else
                cnt[i] = Mul(Mul(C(i - 1, n - i), fac[n - i]),
                             Mul(Mul(fac[tmp], inv_2[tmp / 2]), inv[tmp / 2]));
            sum = Add(sum, cnt[i]);
        }
        
        ll inv_sum = qpow(sum, mod - 2);
        for (int i = 1; i <= n; i++) {
            cout << Mul(cnt[i], inv_sum) << (i == n ? "\n" : " ");
        }
    }
    return 0;
}

An Easy Matrix Problem

©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页