zoukankan      html  css  js  c++  java
  • 2016 Multi-University Training Contest 6

    5/12

    2016 Multi-University Training Contest 6

    官方题解

    打表找规律/推公式 A A Boring Question(BH)

    题意:

      ,意思就是在[0,n]里选择m个数字的相邻数字二项式组合的积的总和。

    思路:

    想了好久,不会,但是这题有300多人过,怀疑人生。。。

    打了个表:

    n=0, m=2, ans=1
    n=1, m=2, ans=3
    n=2, m=2, ans=7
    n=3, m=2, ans=15
    n=4, m=2, ans=31
    n=5, m=2, ans=63
    n=6, m=2, ans=127
    n=7, m=2, ans=900198674
    n=8, m=2, ans=1590575918
    n=0, m=3, ans=1
    n=1, m=3, ans=4
    n=2, m=3, ans=13
    n=3, m=3, ans=40
    n=4, m=3, ans=121
    n=5, m=3, ans=364
    n=6, m=3, ans=1093
    n=7, m=3, ans=-457914394
    n=8, m=3, ans=-624508303
    n=0, m=4, ans=1
    n=1, m=4, ans=5
    n=2, m=4, ans=21
    n=3, m=4, ans=85
    n=4, m=4, ans=341
    n=5, m=4, ans=1365
    n=6, m=4, ans=5461
    n=7, m=4, ans=-914025821
    n=8, m=4, ans=-1903277640
    n=0, m=5, ans=1
    n=1, m=5, ans=6
    n=2, m=5, ans=31
    n=3, m=5, ans=156
    n=4, m=5, ans=781
    n=5, m=5, ans=3906
    n=6, m=5, ans=19531
    n=7, m=5, ans=-681221710
    n=8, m=5, ans=1872878440
    n=0, m=6, ans=1
    n=1, m=6, ans=7
    n=2, m=6, ans=43
    n=3, m=6, ans=259
    n=4, m=6, ans=1555
    n=5, m=6, ans=9331
    n=6, m=6, ans=55987
    n=7, m=6, ans=-199384196
    n=8, m=6, ans=638696943

    按照m排序就能看出规律,想到比赛快结束的时候,最后没时间交题了,好气啊。

    官方解答:

    代码:

    #include <bits/stdc++.h>
    
    typedef unsigned long long ll;
    const int N = 1e5 + 5;
    const int MOD = 1000000007;
    int fact[N];
    
    void init_fact(int n) {
        fact[0] = 1;
        for (int i=1; i<=n; ++i) {
            fact[i] = (ll) fact[i-1] * i % MOD;
        }
    }
    
    int pow_mod(int x, int n, int MOD) {
        int ret = 1;
        for (; n; n>>=1) {
            if (n & 1) ret = (ll) ret * x % MOD;
            x = (ll) x * x % MOD;
        }
        return ret;
    }
    
    int Inv(int x) {
        return pow_mod (x, MOD - 2, MOD);
    }
    
    int n, m;
    int tot;
    int k[N], b[N];
    
    int calc() {
        int ret = 0;
        int tmp = 1;
        for (int i=2; i<=m; ++i) {
            tmp = (ll) tmp * fact[b[i]] % MOD;
        }
        ret = (ll) fact[k[m]] * Inv (fact[k[1]]) % MOD * Inv (tmp) % MOD;
        return ret;
    }
    
    void DFS(int cur, int len, int &ans) {
        if (len == m + 1) {
            ans += calc ();
            return ;
        }
        for (int i=0; i<=n; ++i) {
            k[len] = i; b[len] = k[len] - k[len-1];
            DFS (i, len+1, ans);
        }
    }
    
    int brute(int n, int m) {
        int ret = 0;
        for (int i=0; i<=n; ++i) {
            k[1] = i;
            DFS (i, 2, ret);
        }
        return ret;
    }
    
    int solve() {
        if (n == 0) return 1;
        return (1 + (ll) m * (pow_mod (m, n, MOD) - 1 + MOD) % MOD * Inv (m - 1)) % MOD;
    }
    
    int main() {
        int T;
        scanf ("%d", &T);
        while (T--) {
            scanf ("%d%d", &n, &m);
            //printf ("%d
    ", brute (n, m));
            printf ("%d
    ", solve ());
        }
        return 0;
    }
    

    容斥原理+Lucas定理 B A Simple Chess(BH)

    题意:

      n*m的格子,有r个障碍物,从(1,1)出发不走到障碍物到达(n,m)的方案数。(走法是(x1,y1)->(x1+2,y1+1) or (x1+1,y1+2))

    思路:

      记第一种走法的次数为b次,第二种走法的次数为c次,那么n=1+2c+b,m=1+2b+c。如果不考虑障碍物的话,答案是。那么如果会走到第i个障碍物,那么减去的是从(1,1)到第i个障碍物的位置的方案数(不走到其他的障碍物)乘以从第i个障碍物出发到(n,m)的方案数。注意(n,m)是障碍物的话,方案数直接为0。有了想法后,用代码实现,检验正确性,获得AC,瞬间的快感,这就是ACM的魅力吧。

    代码:

    #include <bits/stdc++.h>
    
    typedef long long ll;
    const int N = 100 + 5;
    const int MOD = 110119;
    
    ll pow_mod(ll x, int n) {
        ll ret = 1;
        for (; n; n>>=1) {
            if (n & 1) ret = ret * x % MOD;
            x = x * x % MOD;
        }
        return ret;
    }
    
    ll Inv(ll x) {
        return pow_mod (x, MOD - 2);
    }
    
    ll fact[MOD];
    
    struct Point {
        ll x, y;
        bool operator < (const Point &rhs) const {
            ll ldis = (x - 1) + (y - 1);
            ll rdis = (rhs.x - 1) + (rhs.y - 1);
            return ldis < rdis;
        }
    }p[N];
    ll res[N];
    ll n, m;
    int r;
    
    void init_fact(int n) {
        fact[0] = 1;
        for (int i=1; i<n; ++i) {
            fact[i] = fact[i-1] * i % MOD;
        }
    }
    
    ll Lucas(ll n, ll k, int p) {
        ll ret = 1;
        while (n && k) {
            ll nn = n % p, kk = k % p;
            if (nn < kk) return 0;
            ret = ret * fact[nn] % p * Inv (fact[kk] * fact[nn-kk] % p) % p;
            n /= p; k /= p;
        }
        return ret;
    }
    
    bool judge_b(ll n, ll m) {
        return (-n + 2 * m - 1) % 3 == 0 && (-n + 2 * m - 1) >= 0;
    }
    
    bool judge_c(ll n, ll m) {
        return (2 * n - m - 1) % 3 == 0 && (2 * n - m - 1) >= 0;
    }
    
    ll get_b(ll n, ll m) {
        return (-n + 2 * m -1) / 3;
    }
    
    ll get_c(ll n, ll m) {
        return (2 * n - m - 1) / 3;
    }
    
    ll solve() {
        //if (r > 0 && p[r-1].x == n && p[r-1].y == m) return 0;
        if (!judge_b (n, m)) return 0;
        if (!judge_c (n, m)) return 0;
        ll b = get_b (n, m);
        ll c = get_c (n, m);
        ll ret = Lucas (b + c, c, MOD);
    
        std::sort (p, p+r);
        memset (res, -1, sizeof (res));
        for (int i=0; i<r; ++i) {
            if (!judge_b (p[i].x, p[i].y)) continue;
            if (!judge_c (p[i].x, p[i].y)) continue;
            if (!judge_b (n-p[i].x+1, m-p[i].y+1)) continue;
            if (!judge_c (n-p[i].x+1, m-p[i].y+1)) continue;
            ll ib = get_b (p[i].x, p[i].y);
            ll ic = get_c (p[i].x, p[i].y);
            res[i] = Lucas (ib+ic, ib, MOD);
    
            for (int j=0; j<i; ++j) {
                if (res[j] == -1) continue;
                if (p[i].x < p[j].x || p[i].y < p[j].y) continue;
                ll nn = p[i].x - p[j].x + 1;
                ll mm = p[i].y - p[j].y + 1;
                if (!judge_b (nn, mm))  continue;
                if (!judge_c (nn, mm)) continue;
                ll jb = get_b (nn, mm);
                ll jc = get_c (nn, mm);
                ll tmp = res[j] * Lucas (jb+jc, jb, MOD) % MOD;
                res[i] = (res[i] - tmp + MOD) % MOD;
            }
            ll nb = get_b (n-p[i].x+1, m-p[i].y+1);
            ll nc = get_c (n-p[i].x+1, m-p[i].y+1);
            ret = (ret - res[i] * Lucas (nb+nc, nb, MOD) % MOD + MOD) % MOD;
        }
        return ret;
    }
    
    int main() {
        init_fact (MOD);
        int cas = 0;
        while (scanf ("%I64d%I64d%d", &n, &m, &r) == 3) {
            bool flag = true;
            for (int i=0; i<r; ++i) {
                scanf ("%I64d%I64d", &p[i].x, &p[i].y);
                if (p[i].x == n && p[i].y == m) flag = false;
            }
            if (!flag) {
                printf ("Case #%d: %I64d
    ", ++cas, 0LL);
                continue;
            }
            printf ("Case #%d: %I64d
    ", ++cas, solve ());
        }
        return 0;
    }
    

    博弈+打表找规律 C A Simple Nim(BH)

    题意:

      除了经典的Nim走法,还多了可以把一堆分成三小堆的走法。

    思路:

      多了一种操作没关系,根据SG定理,只要求出x的所有后继状态的SG函数,SG(x)=mex(S),分成三小堆的状态的SG值看成三个子游戏的Nim和。至于这题的做法,打表找规律即可。

    代码:

    #include <bits/stdc++.h>
    
    int sg[105];
    
    int SG(int n) {
        if (n == 0) return sg[n] = 0;
        if (sg[n] != -1) return sg[n];
        if (n < 3) return sg[n] = n;
        bool vis[1000];
        memset (vis, false, sizeof (vis));
        for (int i=1; i<=n; ++i) {
            for (int j=i; i+j<n; ++j) {
                int k = n - i - j;
                //if (k < i || k < j) continue;
                vis[SG (i) ^ SG (j) ^ SG (k)] = true;
            }
        }
        for (int i=0; i<n; ++i) vis[SG (i)] = true;
        int &ret = sg[n] = 0;
        while (vis[ret]) ret++;
        return ret;
    }
    
    void f() {
        memset (sg, -1, sizeof (sg));
        for (int i=0; i<=100; ++i) {
            printf ("sg[%d]=%d
    ", i, SG (i));
        }
    }
    
    int main() {
        //f ();
        int T;
        scanf ("%d", &T);
        while (T--) {
            int n;
            scanf ("%d", &n);
            long long ans = 0;
            for (int i=0; i<n; ++i) {
                long long x;
                scanf ("%I64d", &x);
                long long sg = x;
                if (x % 8 == 0) sg--;
                if (x % 8 == 7) sg++;
                ans ^= sg;
            }
            puts (ans ? "First player wins." : "Second player wins.");
        }
        return 0;
    }
    

    01背包 H To My Girlfriend(BH)

    题意:

      ,意思是有a[i],a[j],没有a[k],a[l],和为m时的组合数。

    思路:

      想到简单的背包DP,dp[i][j][s1][s2]表示考虑前i个,和为j,且必选了s1个且必不选s2个的方案数。时间复杂度为

    #include <bits/stdc++.h>
    
    const int N = 1e3 + 5;
    const int MOD = 1e9 +7;
    int dp[N][N][3][3];
    int a[N];
    int n, s;
    
    void add_mod(int &a, int b) {
        a += b;
        if (a >= MOD) a -= MOD;
    }
    
    int solve() {
        memset (dp, 0, sizeof (dp));
        dp[0][0][0][0] = 1;
        for (int i=1; i<=n; ++i) {
            for (int j=0; j<=s; ++j) {
                for (int s1=0; s1<=2; ++s1) {
                    for (int s2=0; s2<=2; ++s2) {
                        add_mod (dp[i][j][s1][s2], dp[i-1][j][s1][s2]);  //不选
                        if (j >= a[i]) add_mod (dp[i][j][s1][s2], dp[i-1][j-a[i]][s1][s2]);  //选
                        if (j >= a[i] && s1) add_mod (dp[i][j][s1][s2], dp[i-1][j-a[i]][s1-1][s2]);  //必选
                        if (s2) add_mod (dp[i][j][s1][s2], dp[i-1][j][s1][s2-1]);  //必不选
                    }
                }
            }
        }
        int ret = 0;
        for (int i=1; i<=s; ++i) {
            add_mod (ret, dp[n][i][2][2]);
        }
        return (long long) ret * 4 % MOD;
    }
    
    int main() {
        int T;
        scanf ("%d", &T);
        while (T--) {
            scanf ("%d%d", &n, &s);
            for (int i=1; i<=n; ++i) scanf ("%d", a+i);
            printf ("%d
    ", solve ());
        }
        return 0;
    }

    贪心 J Windows 10(BH)

    题意:

      调音量从p到q,调低的操作,连续的情况下,1,2,4。。。停顿和上升操作都会打断连续,重新从1开始,问最少几次操作。

    思路:

      直观的想法就是拼命的往下降,最后微调(上升或者停顿再下降),考虑到”停顿+一格音量“可以与”上升一格“互换,那么在下降后再上升时考虑能否用停顿替代部分上升,所以要记录停顿的次数,DFS写很好。

    #include <bits/stdc++.h>
    
    typedef long long ll;
    
    ll DFS(ll p, ll q, ll step, ll stop) {
        if (p == q) return step;
        int x = 0;
        while (p - (1<<x) + 1 > q) x++;
        if (p - (1<<x) + 1 == q) return step + x;
        ll up = q - std::max (0LL, (p - (1<<x) + 1));
        ll better = x + std::max (0LL, up - stop);
        return std::min (better + step, DFS (p-(1<<(x-1))+1, q, step+x, stop+1));
    }
    
    int main() {
        int T;
        scanf ("%d", &T);
        while (T--) {
            ll p, q;
            scanf ("%I64d%I64d", &p, &q);
            if (q >= p) {
                printf ("%I64d
    ", q - p);
            } else {
                printf ("%I64d
    ", DFS (p, q, 0, 0));
            }
        }
        return 0;
    }
  • 相关阅读:
    129 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 02 懒汉式的代码实现
    128 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 03 饿汉模式 VS 懒汉模式 01 饿汉式的代码实现
    127 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 02 单例模式概述 01 单例模式的定义和作用
    126 01 Android 零基础入门 02 Java面向对象 06 Java单例模式 01 设计模式概述 01 设计模式简介
    125 01 Android 零基础入门 02 Java面向对象 05 Java继承(下)05 Java继承(下)总结 01 Java继承(下)知识点总结
    leetcode-----121. 买卖股票的最佳时机
    leetcode-----104. 二叉树的最大深度
    Json串的字段如果和类中字段不一致,如何映射、转换?
    Mybatis-Plus的Service方法使用 之 泛型方法default <V> List<V> listObjs(Function<? super Object, V> mapper)
    模糊查询
  • 原文地址:https://www.cnblogs.com/NEVERSTOPAC/p/5738264.html
Copyright © 2011-2022 走看看