2020杭电多校#5(补)

1001 Tetrahedron

题意

​ 一个直角四面体的三条直角边在\([1,\ n]\)范围内随机,求直角顶点到对面的距离的平方倒数(\(\frac{1}{h^2}\))的期望值。

思路

​ 先通过向量计算得到\(\frac{1}{h^2}=\frac{1}{a^2}+\frac{1}{b^2}+\frac{1}{c^2}\), 于是\(E(\frac{1}{h^2})=3E(\frac{1}{a^2}) \quad,其中a\in[1,n]\) ,推出

\[answer=\frac{3}{n} \sum_{i=1}^{n} \frac{1}{i^2} \ (mod \quad 998244353) \]

​ 注意逆元的预处理方法,\(inv[i] = mod-mod/i \ * \ inv[mod\%i]\)

代码

#include 
#define ll long long
using namespace std;
const int maxn = 6e6 + 7;
const int mod = 998244353;

int T, n;
int ni[maxn], sum[maxn];
void init() {
    ni[1] = sum[1] = 1;
    for(int i = 2; i < maxn; i++) {
        ni[i] = mod - 1LL * mod/i * ni[mod%i] % mod;
        sum[i] = sum[i-1] + 1LL * ni[i] * ni[i] % mod;
        sum[i] %= mod;
    }
}
ll qpow(ll a, ll b) {
    ll ans = 1;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    init();
    cin >> T;
    while(T--) {
        cin >> n;
        cout << 1LL * sum[n] * 3 % mod * qpow(n, mod - 2) % mod << endl;
    }
    return 0;
}

1003 Boring Game

题意

​ 有n张纸叠在桌面上,将这些纸从左到右折叠k次,一共分层\(2*n*(1<层,对这些层从1开始编号,给一组折叠后编号,问折叠前这些编号从上到下,从左到右的序列。

思路

​ 用数组来模拟,对于每一次折叠,找到折叠的中点,然后将中点上面的一次逆序加到下面的数组中去。

代码

#include 
#define ll long long
using namespace std;
const int maxn = 5e5 + 7;
const int mod = 1e9 + 7;

int T, n, k;
vector v[maxn];
void slove(int l, int r) {
    int mid = (l + r) / 2, now = mid + 1;
    for(int i = mid; i >= l; i--) {
        for(int j = v[i].size() - 1; j >= 0; j--) {
            v[now].push_back(v[i][j]);
        }
        now++;
    }
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    cin >> T;
    while(T--) {
        cin >> n >> k;
        int len = 2 * n * (1 << k);
        for(int i = 0; i < maxn; i++) v[i].clear();
        for(int i = 0; i < len; i++) {
            int temp; cin >> temp;
            v[i].push_back(temp);
        }
        int l = 0, r = len - 1;
        for(int _ = 0; _ < k; _++) {
            slove(l, r);
            l += (r - l) / 2 + 1;
        }
        for(int i = l; i <= r; i++) {
            reverse(v[i].begin(), v[i].end());
            for(int j = 0; j < v[i].size(); j++) {
                cout << v[i][j];
                if(i == r && j == v[i].size() - 1) cout << endl;
                else cout << ' ';
            }
        }
    }
    return 0;
}

1009 Paperfolding

题意

​ 给一张纸,水平对折,竖直对折,一共进行n次(意味着有\(2^n\)种折法),最后将纸剪一个十字,剪出来会分成很多块,求块数的数学期望。

思路

​ 假设水平折叠了x次,竖直折叠了y次,将折叠后的纸展开会发现,剪开的痕迹就是将原纸张竖直方向上剪了\(2^x\)刀,水平方向上剪了\(2^y\)刀,因此总共剪出了\((2^x+1)*(2^y+1)\)个块。

​ 因此期望就是

\[\begin{align} ans &= \frac{1}{2^n} \ \sum_{i=0}^{n} \ C_n^i \ (2^i+1)*(2^{n-i}+1) \\ &= \frac{1}{2^n} \ \sum_{i=0}^{n} \ C_n^i \ (2^n+2^i+2^{n-i}+1) \\ &= 2^n+1+2* \frac{1}{2^n} \sum_{i=0}^{n} \ C_n^i 2^i \\ &= 2^n+1+2*\frac{3^n}{2^n} \end{align} \]

代码

#include 
#define ll long long
using namespace std;
const int maxn = 1e5 + 7;
const int mod = 998244353;

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

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    ll inv2 = qpow(2, mod - 2);
    cin >> T;
    while(T--) {
        cin >> n;
        ll ans = 1 + qpow(2, n % (mod - 1)) + 2 * qpow(3 * inv2, n % (mod - 1));
        ans %= mod;
        cout << ans << endl;
    }
    return 0;
}

1012 Set1

题意

​ 一个初始元素为\(\{1,...,n\}\)的集合依次做两个操作,直到只剩一个元素

  • 去除集合中最小的元素

  • 随机去除一个元素

​ 问每个数字被剩下的期望值

思路

​ 对于第\(i\)个元素,能剩下的条件是他左边的元素个数不少于右边的元素个数,而且右边的元素个数都是被第二种操作去除。

​ 于是对于每一个数留下来的方案数有\(cnt[i]=C_{r}^{l} \ r! \ \frac{(r-l)!}{(2!)^{(r-l)/2} \ \frac{r-l}{2}}\),其中\(l\)\(i\)左边的数的个数,\(r\)\(i\)右边的数的个数。

​ 答案就是每一个的方案数\(cnt[i]\)除方案数求和\(sum\)

代码

#include 
#define ll long long
using namespace std;
const int maxn = 5e6 + 7;
const int mod = 998244353;

int T, n;
int cnt[maxn], fac[maxn], inv[maxn], sum;

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

void init() {
    fac[0] = inv[0] = 1;
    for(int i = 1; i < maxn; i++) fac[i] = (ll)fac[i - 1] * i % mod;
    inv[maxn - 1] = qpow(fac[maxn - 1], mod - 2);
    for(int i = maxn - 2; i >= 1; i--) inv[i] = (ll)inv[i + 1] * (i + 1) % mod;
}

ll C(ll n, ll m) {
    return (ll)fac[n] * inv[m] % mod * inv[n - m] % mod;
}

int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    freopen("data.in", "r", stdin);
    //freopen("data.out", "w", stdout);
    init();
    cin >> T;
    while(T--) {
        sum = 0;
        cin >> n;
        for(int i = 1; i <= n; i++) {
            int l = i-1, r = n-i;
            if(l >= r) {
                int res = (ll)C(l, r) * fac[r] % mod;
                int temp = qpow(2, (l-r)/2);
                temp = qpow(temp, mod - 2);
                res = (ll)res * fac[l-r] % mod * temp % mod;
                res = (ll)res * inv[(l-r)/2] % mod;
                cnt[i] = res;
                sum = ((ll)sum + cnt[i]) % mod;
            }
            else cnt[i] = 0;
        }
        sum = qpow(sum, mod - 2);
        for(int i = 1; i <= n; i++) {
            cout << (ll)cnt[i] * sum % mod;
            if(i != n) cout << ' ';
        }
        cout << endl;
    }
    return 0;
}

你可能感兴趣的:(2020杭电多校#5(补))