• 5.11 考试解题报告


    5.11 考试解题报告

    前言

    估分 : (100 + 30 + 0 = 130)

    实际得分 : (100 + 30 + 0 = 130)

    除了 (T1) 是个高精大水题之外都是不可做题,(T3) 连题目都没看懂。

    第一次考试对着题目看了 20 分钟没看懂题目。

    把考试的题目整理到题库里了,可以看了。

    考场上的心路历程 :

    • 开始看 (T1) 阶乘之和 ?大水题,写个高精就行了,写了 30 分钟,用计算器一测,没问题。
    • 看了 (T2) 的第一眼,组合数学?希望自己能推出式子来。
    • 20 分钟以后,好像还要用容斥?继续推。
    • 30 分钟以后,这是什么神仙题目,算了,先把 (T3) 看看。
    • 看了 10 分钟,题目是什么意思 ?连个样例解释都不给。
    • 又看了 10 分钟,一脸懵逼,他这是要求什么 ?不管了,看 (T2)
    • 继续推 (T2),心中已经将 (T3) 放弃,题目都看不懂,又过了 20 分钟。
    • (T2) 实在推不出来了,写爆搜吧,还有 30 分。
    • 20 分钟后,写完了,一测样例,输出 0 ?有点小慌。
    • 5 分钟后,哦,我的 dfs 没回溯,自己把自己逗笑了。
    • 还有一些时间,再看看 (T3) 吧。
    • 之后写了个 (O(?)) 的暴力,没过样例(输出差了老远),于是换了随机数。
    • 对着 (T2) 又沉思了 (10) 分钟 + 看了看 (T1),交卷走人。

    T1

    (Link)

    Solution

    • 前三十分,直接模拟即可。
    • 后面 70 分,明显是要高精,也是直接模拟。

    由于我对自己写的高精不放心,还是测试的分治了 /cy

    注意高精乘的时候初始别忘附为 1。

    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #define LL long long
    using namespace std;
    const int Maxk = 1e4 + 10;
    LL a[110],Ans;
    int n;
    int maxn = -1;
    struct Gao {
      int z[Maxk];
      int len_;
      Gao () {
        memset(z,0,sizeof z);
        len_ = 0;
      }
    }A[102];
    inline int Max(int a,int b) {return a > b ? a : b;}
    inline int read()
    {
    	int s = 0, f = 0;char ch = getchar();
    	while (!isdigit(ch)) f |= ch == '-', ch = getchar();
    	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    Gao operator + (const Gao &c,const Gao &d) 
    {
      Gao B;
      B.len_ = Max(c.len_,d.len_) + 1;
      for(int i = 1;i <= B.len_;i ++) {
        B.z[i] += c.z[i] + d.z[i];
        if(B.z[i] >= 10) {
          B.z[i] -= 10;
          B.z[i + 1] += 1;
        }
      }
      while(B.len_ > 1 && B.z[B.len_] == 0) B.len_ --;
      return B;
    } 
    Gao operator * (const Gao &c,int nu)
    {
      Gao C,d;
      int cnt = 0;
      for(;nu;nu /= 10) {
        d.z[++ cnt] = nu % 10;//这样会使变为倒序 
      }
      d.len_ = cnt;
      C.len_ = c.len_ + d.len_ + 1;
      for(int i = 1;i <= c.len_;i ++) {
        for(int j = 1;j <= d.len_;j ++) {
          C.z[i + j - 1] += c.z[i] * d.z[j];
          if(C.z[i + j - 1] >= 10) {
            int k = C.z[i + j - 1] % 10;
            C.z[i + j] += C.z[i + j - 1] / 10;
            C.z[i + j - 1] = k;
          }
        }   
      } 
      while(C.len_ > 1 && C.z[C.len_] == 0) C.len_ --;
      return C;
    }
    void Solve()
    {
      for(int i = 1;i <= n;i ++) {
        LL sum = 1;
        if(a[i] == 0) a[i] = 1;
        for(int j = 1;j <= a[i];j ++) {
          sum *= j;
        }
        Ans += sum;
      }
      cout << Ans << endl;
      return;
    }
    signed main()
    {
    	freopen("a.in","r",stdin);
    	freopen("a.out","w",stdout);
    	n = read();
    	for(int i = 1;i <= n;i ++) a[i] = read(),maxn = Max(maxn,a[i]);
    	if(maxn <= 10) {
    	  Solve();
    	  return 0;
      }
      for(int i = 1;i <= n;i ++) {
        A[i].len_ = 1;
        A[i].z[1] = 1;
      }
      Gao Sum;
      for(int i = 1;i <= n;i ++) {
        if(a[i] == 0) a[i] = 1;
        for(int j = 1;j <= a[i];j ++) {
          A[i] = A[i] * j;
        }
        Sum = Sum + A[i];
      }
      for(int i = Sum.len_;i >= 1;i --) cout << Sum.z[i];
      return 0;
    }
    

    T1 连写带调用了 30 分钟,幸好没考高精减和高精除,两个都没学。

    T2

    (Link)

    Solution

    首先,这是一个容斥定理的题目,我们考虑用全集减去他的补集。

    首先全集是很容易的出来的,就是 (k ^ {n imes m}),就是 (n imes m) 个点随便染色,根据乘法原理,显然成立。

    之后考虑容斥,我们开始删去不合法的情况。

    • 当只有行不合法的时候

    这个时候我们考虑删去 (n) 行中有 (1) 行为相同颜色的方案数,但是我们删去的话明显会删多,所以还要将两行为相同颜色的加上,这样反复,显然是个容斥定理,我们枚举删除的行数,从 (i = 1 sim n),当 (i) 为奇数的时候就减去,否则加上。

    那么公式是什么 :

    考虑当前我们随机从 (n) 行中选了 (i) 行,所以是 (dbinom{n}{i})

    之后我们选择的行中,因为每行都颜色相同,所以颜色共有 (k ^ i) 种情况。

    剩下的矩形不就随便上颜色了,所以是 (k ^ {(n - i) imes m}) 种。

    所以我们得到的式子就是 :

    [(-1) ^ idbinom{n}{i} imes k ^ i imes k ^ {(n - i) imes m} ]

    • 只有列不合法的时候

    和上面的情况相同,也是容斥,最后得出来的式子长这样 :

    [(-1) ^ i dbinom{m}{i} imes k ^ i imes k ^ {(m - i) imes n} ]

    • 行列都不符合的时候

    依旧是一个容斥,不过比较复杂。

    先从简单的情况开始,我们先从 1 行颜色相同并且 1 列颜色相同的情况开始。

    这时候是从 (n) 中选出了 1 行和从 (m) 中选出了 1 列的时候,颜色有 (k) 种,并且其余的格子都是随便填的情况,即 :

    [k imes dbinom{n}{1} dbinom{m}{1} imes k ^ {(n - 1)(m - 1)} ]

    由此推广到所有情况 :

    [Ans = k sum_{i = 1} ^ n sum_{j = 1} ^ m (-1) ^ {i + j}dbinom{n}{i} dbinom{m}{j} k ^ {(n - i)(m - j)} ]

    发现 (n,m leq 10 ^ 6),所以 (O(n ^ 2)) 枚举是肯定过不了的。

    开始化简 :

    [egin{aligned} Ans &= k sum_{i = 1} ^ n sum_{j = 1} ^ m (-1) ^ {i + j}dbinom{n}{i} dbinom{m}{j} k ^ {(n - i)(m - j)} \ &= k sum_{i = 1} ^ n dbinom{n}{i} sum_{j = 1} ^ m (-1) ^ {i + j} dbinom{m}{j} k ^ {(n - i)(m - j)} \ &= k sum_{i = 1} ^ n dbinom{n}{i} (1 + k ^ {n - i}) ^ m (-1) ^ {i} \ &= k sum_{i = 1} ^ n (-1) ^ {i}dbinom{n}{i} (1 + k ^ {n - i}) ^ m end{aligned} ]

    中间第 (2 o 3) 用了二项式定理。

    所以我们就能过掉这个题目了,还没写,粘一下std。

    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <iostream>
    #include <algorithm>
    #include <map>
    #include <set>
    #include <queue>
    #include <vector>
    using namespace std;
    typedef long long ll;
    typedef unsigned int uint;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    #define fi first
    #define se second
    #define MP make_pair
    
    ll read()
    {
        ll v = 0, f = 1;
        char c = getchar();
        while (c < 48 || 57 < c) {if (c == '-') f = -1; c = getchar();}
        while (48 <= c && c <= 57) v = (v << 3) + v + v + c - 48, c = getchar();
        return v * f;
    }
    
    const ll MOD = 998244353, MOD2 = MOD - 1;
    const int N = 1010000;
    
    ll n, m, K;
    
    ll fac[N], inv[N];
    
    ll pw(ll a, ll b)
    {
        a = (a % MOD + MOD) % MOD;
        b = (b % MOD2 + MOD2) % MOD2;
        ll re = 1;
        while (b)
        {
            if (b & 1)
                re = re * a % MOD;
            a = a * a % MOD;
            b >>= 1;
        }
        return re;
    }
    
    ll C(int n, int m)
    {
        if (n < 0 || m < 0 || n - m < 0) return 0;
        return fac[n] * inv[m] % MOD * inv[n - m] % MOD;
    }
    
    int main()
    {
        //freopen("b.in", "r", stdin);
        //freopen("b.out", "w", stdout);
        fac[0] = 1;
        for (ll i = 1; i <= 1000000; i++)
            fac[i] = fac[i - 1] * i % MOD;
        inv[0] = inv[1] = 1;
        for (ll i = 2; i <= 1000000; i++)
            inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
        for (ll i = 1; i <= 1000000; i++)
            inv[i] = inv[i - 1] * inv[i] % MOD;
        n = read(), m = read(), K = read();
        ll ans = pw(K, n * m);
        for (ll i = 1; i <= n; i++)
            if (i & 1)
                ans = (ans - C(n, i) * pw(K, i) % MOD * pw(K, (n - i) * m) % MOD + MOD) % MOD;
            else
                ans = (ans + C(n, i) * pw(K, i) % MOD * pw(K, (n - i) * m) % MOD) % MOD;
        for (ll i = 1; i <= m; i++)
            if (i & 1)
                ans = (ans - C(m, i) * pw(K, i) % MOD * pw(K, (m - i) * n) % MOD + MOD) % MOD;
            else
                ans = (ans + C(m, i) * pw(K, i) % MOD * pw(K, (m - i) * n) % MOD) % MOD;
        for (ll i = 1; i <= n; i++)
            if (i & 1)
                ans = (ans - C(n, i) * K % MOD * ((pw(pw(K, n - i) - 1, m) - pw(K, (n - i) * m) + MOD) % MOD) % MOD + MOD) % MOD;
            else
                ans = (ans + C(n, i) * K % MOD * ((pw(pw(K, n - i) - 1, m) - pw(K, (n - i) * m) + MOD) % MOD) % MOD) % MOD;
        printf("%lld
    ", ans);
    }
    

    T3

    (Link)

    玄学题面,盯着看了半天都没看懂,甚至不知要求啥,所以到现在题解也没看懂,明天再看看。

  • 相关阅读:
    路由器只要能连接上,就能得到密码,
    jmeter上传文件搞了一天,才搞定,没高人帮忙效率就是低,赶紧记下来,以备后用
    1关0不关
    AJAX学习
    建表原则
    设计模式——代理模式
    jdk动态代理机制
    ArrayList源码分析
    Java集合类:HashMap (基于JDK1.8)
    SpringMVC的数据转换、格式化和数据校验
  • 原文地址:https://www.cnblogs.com/Ti-despair/p/14757689.html
Copyright © 2020-2023  润新知