zoukankan      html  css  js  c++  java
  • 2016多校第六场题解(hdu5793&hdu5794&hdu5795&hdu5800&hdu5802)

    这场就做出一道题,怎么会有窝这么辣鸡的人呢?

    1001 A Boring Question(hdu 5793)

    很复杂的公式,打表找的规律,最后是m^0+m^1+...+m^n,题解直接是(m^(n+1)-1)/(m-1),长姿势,原来还能化简……

    我既然不会推公式,也没啥好写的。写一下我打表的代码吧……

    #include <cstdio>
    
    typedef long long ll;
    
    int n, m;
    ll sum;
    ll fac[300];
    int a[300];
    
    void init()
    {
        fac[0] = 1;
        for (int i = 1; i <= 20; ++i) fac[i] = fac[i-1] * i;
    }
    
    void dfs(int p)
    {
        if (p == m) {
            ll tmp = 1;
            for (int i = 0; i < m-1; ++i) {
                tmp *= fac[ a[i+1] ] / fac[ a[i] ] / fac[ a[i+1]-a[i] ];
            }
            sum += tmp;
            return ;
        }
        for (int i = a[p-1]; i <= n; ++i) {
            a[p] = i;
            dfs(p+1);
        }
    }
    
    int main(int argc, char const *argv[])
    {
        init();
    
        for (int i = 0; i <= 5; ++i) {
            for (int j = 2; j <= 8; ++j) {
                sum = 0;
                n = i, m = j;
                dfs(0);
                printf("%-8lld", sum);
            }
            printf("
    ");
        }
    
        return 0;
    }

    1002 A Simple Chess(hdu 5794)

    一个棋盘,走棋的姿势要满足(x1-x2)^2+(y1-y2)^2==5,也就是以“日”字走,且只能向右下走。

    其中有一些障碍不能经过,注意障碍有可能在终点,求从(1,1)走到(n,m)的路径数。

    容斥+组合数 这题的简单版CF559C(对啊,我做过这题,我还是没做出来,wa了十多次,啦啦啦)

    over是防止重点的,感觉不会有重点,但是比赛时是实在没辙了=_=#

    这道题教育我,取模需谨慎!- -

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    const ll MOD = 110119;
    const int MAX_P = 2000005;
     
    ll powMod(ll a, ll b, ll mod)
    {
        ll res = 1;
        while (b) {
            if (b & 1) res = res * a % mod;
            a = a * a % mod;
            b >>= 1;
        }
        return res;
    }
     
    ll fac[MAX_P];
    void getFact()
    {
        fac[0] = 1;
        for (int i = 1; i <= 2000000; ++i)
            fac[i] = fac[i - 1] * i % MOD;
    }
     
    ll Lucas(ll n, ll m, ll p)
    {
        ll res = 1;
        while (n && m) {
            ll a = n % p;
            ll b = m % p;
            if (a < b) return 0;
            res = res * fac[a] % p * powMod(fac[b] * fac[a - b] % p, p - 2, p) % p;
            n /= p;
            m /= p;
        }
        return res;
    }
    
    struct Point {
        ll x, y;
        Point(ll x, ll y):x(x),y(y){}
        Point(){}
        bool operator<(const Point a) const
        {
            if (x == a.x) return y < a.y;
            return x < a.x;
        }
        bool operator==(const Point a) const
        {
            if (x == a.x && y == a.y) return true;
            return false;
        }
    } p[2005];
    
    
    ll cal(Point a, Point b)
    {
        ll dx = b.x - a.x;
        ll dy = b.y - a.y;
        ll r, c;
        if ((dx*2-dy)%3 || (dy*2-dx)%3) return 0;
        ll inv = powMod(3, MOD-2, MOD);
        r = (2 * dx - dy) / 3;
        c = (2 * dy - dx) / 3;
        if (r < 0 || c < 0) return 0;
        if (c == 0 || r == 0) return 1;
        return Lucas(r+c, r, MOD);
    }
     
    ll ans[2005];
    bool over[2005];
    int main()
    {
        //freopen("in", "r", stdin);
        ll m, n, r;
        getFact();
        int cas = 0;
        while (cin >> m >> n >> r) {
            printf("Case #%d: ", ++cas);
            Point s(1, 1);
            for (int i = 0; i < r; ++i) scanf("%lld%lld", &p[i].x, &p[i].y);
            p[r].x = m, p[r].y = n;
            sort(p, p + r);
            if (p[r-1].x == m && p[r-1].y == n) {
                printf("0
    ");
                continue;
            }
            memset(over, false, sizeof over);
            for (int i = 1; i < r; ++i) {
                if (p[i] == p[i-1]) over[i] = true;
            }
            for (int i = 0; i <= r; ++i) {
                if (over[i]) continue;
                ans[i] = cal(s, p[i]);
                for (int j = 0; j < i; ++j) {
                    if (over[j]) continue;
                    if (p[j].x < p[i].x && p[j].y < p[i].y) {
                        ans[i] = ((ans[i] - cal(p[j], p[i]) * ans[j] % MOD) % MOD + MOD) % MOD;
                    }
                }
            }
            ans[r] = (ans[r] + MOD) % MOD;
            printf("%lld
    ", ans[r]);
        }
        return 0;
    }

    1003 A Simple Nim(hdu 5795)

    nim博弈变形

    有n堆糖,每次拿走一堆的任意个, 或者把一堆分成三堆。

    对一堆求SG函数值,然后打表找规律,感觉不难,但是没想明白,后来有一个网友提醒我(额 虽然比赛时这样不太好……),终于开始写,其实一开始我是蒙蔽的,写写的突然清晰了,但是错了一个数……sg[2]应该是2,我竟然随手写成了0,妈蛋T^T

    只能说掌握的不好0。0

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    #define PF(x) cout << "debug: " << x << " ";
    #define EL cout << endl;
    #define PC(x) puts(x);
    
    typedef long long ll;
    
    const int N = 1000005;
    const int MOD = 1e9+7;
    
    int a[N];
    int sg[N];
    
    int get_sg(int x)
    {
        if (x == 0) return 0;
        if (x == 1) return 1;
        if (x == 2) return 2;
    
        if (sg[x] != -1) return sg[x];
    
        int mex[200000] = {0};
    
        for (int i = 1; i < x; ++i) {
            for (int j = i; j < x-i; ++j) {
                int k = x - i - j;
                if (k <= 0) break;
                int tmp = get_sg(i) ^ get_sg(j) ^ get_sg(k);
                mex[tmp] = 1;
            }
        }
    
        for (int i = 0; i < x; ++i) {
            mex[get_sg(i)] = 1;
        }
    
        for (int i = 0; ; i++) {
            if (!mex[i]) return sg[x] = i;
        }
    }
    
    int main(int argc, char const *argv[])
    {
        // memset(sg, -1, sizeof sg);
    
        // for (int i = 0; i < 100; ++i) {
        //     cout << i << " " << get_sg(i) << endl;
        // }
    
    
        //freopen("in", "r", stdin);
        int T;
        scanf("%d", &T);
        while (T--) {
            int n;
            scanf("%d", &n);
            int ans = 0;
            for (int i = 0; i < n; ++i) {
                scanf("%d", a+i);
                if (a[i] % 8 == 0) a[i]--;
                else if (a[i] % 8 == 7) a[i]++;
                ans ^= a[i];
            }
            printf("%s
    ", ans ? "First player wins.":"Second player wins.");
        }
        return 0;
    }

    1008 To My Girlfriend(hdu5800)

    题意:f(i,j,k,l,m)表示n个物体,必须选择第i,j个,一定不选择第k,l个,且物品重量和为m的选择方法数。求 其中i,j,k,l各不相同。

    题解:dp。

    令dp[i][j][s1][s2]表示前i个物品填了j的体积,有s1个物品选为为必选,s2个物品选为必不选的方案数(0<=s1,s2<=2),则有转移方程dp[i][j][s1][s2] = dp[i - 1][j][s1][s2] + dp[i - 1][j - a[i]][s1 - 1][s2] + dp[i - 1][j][s1][s2 - 1],边界条件为dp[0][0][0][0] = 1,时间复杂度O(NS*3^2)。

    dp[i][j][s1][s2] = dp[i - 1][j][s1][s2] + dp[i-1][j-a[i]][s1][s2] + dp[i - 1][j - a[i]][s1 - 1][s2] + dp[i - 1][j][s1][s2 - 1] 

             ^不必选a[i] 不选          ^不必选 选a[i]                 ^ 必选a[i]                               ^必不选a[i]

    dp开成long long会超内存,所以改成int ,注意不要爆,也可以改成滚动数组。

    因为f(i,j,k,l,m)==f(j,i,k,l,m)==f(i,j,l,k,m)==f(j,i,l,k,m) 所以一个dp[n][s][2][2]是会被重复计算4次的,答案要*4.

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int MOD = 1e9+7;
    const int N = 1005;
    int a[N];
    int dp[N][N][3][3];
    
    void up(int &x, int y)
    {
        x += y;
        if (x >= MOD) x -= MOD;
    }
    
    int main(int argc, char const *argv[])
    {
        //freopen("in", "r", stdin);
        int T;
        scanf("%d", &T);
        while (T--) {
            int n, s;
            scanf("%d%d", &n, &s);
            for (int i = 1; i <= n; ++i) scanf("%d", a+i);
            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) {
                            int &now = dp[i][j][s1][s2];
                            up(now, dp[i-1][j][s1][s2]);    //非必选 不选
                            if (j >= a[i]) up(now, dp[i-1][j-a[i]][s1][s2]);    // 非必选 选
                            if (s1 > 0 && j >= a[i]) up(now, dp[i-1][j-a[i]][s1-1][s2]);    // 必选
                            if (s2 > 0) up(now, dp[i-1][j][s1][s2-1]);    // 必不选
                        }
                    }
                }
            }
            int ans = 0;
            for (int j = 0; j <= s; ++j) {
                up(ans, dp[n][j][2][2]);
            }
            printf("%lld
    ", (ll)ans * 4 % MOD);
        }
        return 0;
    }

    1010 Windows 10(hdu5802)

    题意:(比赛时就没看懂题)音量上调是一秒提升1db,下降时,第一秒1db,连续下降每秒下降前一秒的一倍。求p~q需要几秒。

    题解:感觉这题属于比较好想但是不易写代码的,如果p≤q,显然直接出结果,否则,先降到最接近q的位置,低于q就一秒一秒加上来,大于q就递归求解。

    由于每两次递减需要停顿,所以可以把上升的次数放在递减之间,于是递归时需要记录有多少次按住的递减。

    同时因为音量不能小于0,所以要特殊考虑一下。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    ll pow2[31];
    ll p, q;
    
    void init()
    {
        pow2[1] = 1;
        for (int i = 2; i < 31; ++i) pow2[i] = pow2[i-1] * 2;
        for (int i = 2; i < 31; ++i) pow2[i] += pow2[i-1];
    }
    
    ll cal(ll p, ll ti)//ti是下压的次数 中间要停顿或者反向哦
    {
        if (p-q == 0) return ti - 1;
        if (p-q == 1) return ti + 1;
    
        int pos = lower_bound(pow2, pow2+31, p-q) - pow2;
        ll g = pow2[pos];
        ll s = pow2[pos-1];
        ll ans;
        // g≥p-q
        if (p-g < 0) ans = max(ti, q) + pos;
        else ans = max(ti, g-p+q) + pos;
        // s<p-q
        ans = min(ans, pos-1+cal(p-s, ti+1));
        return ans;
    }
    
    int main(int argc, char const *argv[])
    {
        //freopen("in", "r", stdin);
        init();
        int T;
        cin >> T;
        while (T--) {
            scanf("%lld%lld", &p, &q);
            if (p <= q) printf("%lld
    ", q-p);
            else printf("%lld
    ", cal(p, 0));
        }
        return 0;
    }

    怎么会有窝这么弱的人呢?

  • 相关阅读:
    第2次实践作业
    第1次实践作业
    软工实践个人总结
    2019 SDN大作业
    第08组 Beta版本演示
    第八章学习小结
    第七章学习小结
    第六章学习小结
    第五章学习小结
    第4章学习小结
  • 原文地址:https://www.cnblogs.com/wenruo/p/5737767.html
Copyright © 2011-2022 走看看