2016 Multi-University Training Contest 6

来源:互联网 发布:百度深圳分公司 知乎 编辑:程序博客网 时间:2024/06/07 06:48

A
显然有规律可寻

#include <iostream>#include <cstdlib>#include <cstdio>#include <algorithm>#include <string>#include <map>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <vector>#include <set>using namespace std;typedef long long LL;typedef pair<int, int> pii;const int MAXN = 1e5 + 10;const int INF = 1e9 + 10;const int MOD = 1e9 + 7;LL pow_mod(LL a, LL n) {    LL ans = 1LL;    while(n) {        if(n & 1LL) {            ans = ans * a % MOD;        }        a = a * a % MOD;        n >>= 1LL;    }    return ans;}int main(){    int t; scanf("%d", &t);    while(t--) {        LL n, m; scanf("%lld%lld", &n, &m);        printf("%lld\n", (pow_mod(m, n + 1) - 1 + MOD) % MOD * pow_mod(m - 1, MOD - 2) % MOD);    }    return 0;}

B
题意:每次从(x, y)可以到(x + 2, y + 1),(x + 1, y + 2)。中间有m个格子是坏的,问你从(1, 1) 到 (n, m)的方案数。

dp[i]表示到达第i个坏格子且不经过其他坏格子的方案数。
dp[i]=i1j=1dp[j]

#include <iostream>#include <cstdlib>#include <cstdio>#include <algorithm>#include <string>#include <map>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <vector>#include <set>#define ll o<<1#define rr o<<1|1using namespace std;typedef long long LL;typedef pair<LL, LL> pii;const int MAXN = 2e5 + 10;const int MOD = 110119;void add(LL &x, LL y) { x += y; if(x < 0) x += MOD; x %= MOD; }LL fac[MAXN];void getfac(LL p) {    fac[0] = 1 % p;    for(LL i = 1; i <= p; i++) {        fac[i] = fac[i-1] * i % p;    }}LL pow_mod(LL a, LL n, LL p) {    LL ans = 1LL;    while(n) {        if(n & 1)            ans = ans * a % p;        a = a * a % p;        n >>= 1;    }    return ans;}LL C(LL n, LL m, LL p) {    if(m > n) return 0;    else return fac[n] * pow_mod(fac[m] * fac[n-m] % p, p - 2, p) % p;}LL Lucas(LL n, LL m, LL p) {    if(m == 0) {        return 1 % p;    }    else {        return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;    }}LL Solve(LL x1, LL y1, LL x2, LL y2) {    if(x1 > x2 && y1 > y2) {        swap(x1, x2); swap(y1, y2);    }    if(x1 <= x2 && y1 <= y2) {        LL d = 2 * y2 - 2 * y1 + x1 - x2;        if(d >= 0 && d % 3 == 0) {            LL y = d / 3; d = x2 - y - x1;            if(d < 0 || d & 1) return 0;            LL x = d / 2;            //cout << x << ' ' << y << endl;            return Lucas(x + 1 + y - 1, x + 1 - 1, MOD);        }    }    return 0;}pii a[110];LL dp[110];int main(){    getfac(MOD);    LL n, m; int r, kcase = 1;    while(scanf("%lld%lld%d", &n, &m, &r) != EOF) {        for(int i = 1; i <= r; i++) {            scanf("%lld%lld", &a[i].first, &a[i].second);            dp[i] = 0;        }        sort(a + 1, a + r + 1);        a[r + 1] = pii(n, m); r++; dp[r] = 0;        for(int i = 1; i <= r; i++) {            LL sum = 0;            for(int j = 1; j < i; j++) {                if(a[i].first >= a[j].first && a[i].second >= a[j].second) {                    add(sum, dp[j] * Solve(a[j].first, a[j].second, a[i].first, a[i].second) % MOD);                }            }            add(dp[i], Solve(1, 1, a[i].first, a[i].second) - sum);        }        printf("Case #%d: %lld\n", kcase++, dp[r]);    }    return 0;}

C
题意:有n堆石子,每次可以选择从某一个非空堆里面取出不少于1数目的石子,也可以选择将该堆分为三堆石子(不允许为空)。

SG打表。

#include <iostream>#include <cstdlib>#include <cstdio>#include <algorithm>#include <string>#include <map>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <vector>#include <set>using namespace std;typedef long long LL;typedef pair<int, int> pii;const int MAXN = 1e6 + 10;const int INF = 1e9 + 10;const int MOD = 1e9 + 7;int a[MAXN];int main(){    //freopen("out.txt", "w", stdin);//    sg[0] = 0, sg[1] = 1, sg[2] = 2;//    for(int i = 3; i <= 200; i++) {//        sg[i] = Work(i);//    }//    for(int i = 3; i <= 200; i++) {//        printf("%d %d %d\n", i, sg[i], sg[sg[i]]);//    }    int t; scanf("%d", &t);    while(t--) {        int n; scanf("%d", &n);        LL ans = 0;        for(int i = 1; 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(ans ? "First player wins.\n" : "Second player wins.\n");    }    return 0;}

H
日狗,看了好久不懂题意?
题意:
ni=1nj=1nk=1nl=1sm=1f(i,j,k,l,m)(i,j,k,laredifferent)
意思是让你找到若干个子集,使得a[i],a[j]必选,a[k],a[l]必不选且和<=m
dp[i][j][k][l]表示前i个数和为j且k个必选l个必不选的方案数。

#include <iostream>#include <cstdlib>#include <cstdio>#include <algorithm>#include <string>#include <map>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <vector>#include <set>#define ll o<<1#define rr o<<1|1using namespace std;typedef long long LL;typedef pair<int, int> pii;const int MAXN = 2e5 + 10;const int MOD = 1e9 + 7;void add(int &x, int y) { x += y; if(x >= MOD) x -= MOD; }int dp[1001][1001][3][3];int a[1001];int main(){    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 k = 0; k <= 2; k++) {                    for(int l = 0; l <= 2; l++) {                        if(j >= a[i]) {                            add(dp[i][j][k][l], dp[i - 1][j - a[i]][k][l]);                            if(k - 1 >= 0) {                                add(dp[i][j][k][l], dp[i - 1][j - a[i]][k - 1][l]);                            }                        }                        if(l - 1 >= 0) {                            add(dp[i][j][k][l], dp[i - 1][j][k][l - 1]);                        }                        add(dp[i][j][k][l], dp[i - 1][j][k][l]);                    }                }            }        }        int ans = 0;        for(int i = 1; i <= s; i++) {            add(ans, dp[n][i][2][2]);        }        printf("%lld\n", 1LL * 4 * ans % MOD);    }    return 0;}

J
题意:每次可以选择加一、不动、减一。选择减的话,如果上次减去x的话这次要减2*x,反之减1。问你最少需要多少次p可以到q。

思路:我们有两种决策——p一直升到大于q的最小值或者降到小于q的最大值,其实二者代价是相同的。我们就考虑降的策略时,中间记录一下需要停顿的次数rest,最后一次加的时候取差值和rest最大值即可。因为我们可以把停顿一次用做一次加操作。

#include <iostream>#include <cstdlib>#include <cstdio>#include <algorithm>#include <string>#include <map>#include <cstring>#include <stack>#include <queue>#include <cmath>#include <vector>#include <set>#define ll o<<1#define rr o<<1|1using namespace std;typedef long long LL;typedef pair<LL, LL> pii;const int MAXN = 2e5 + 10;const int MOD = 110119;void add(LL &x, LL y) { x += y; if(x < 0) x += MOD; x %= MOD; }LL fac[64];int Work(LL n) {    int k = 0;    while(fac[k] - 1 <= n) k++;    return k;}LL Solve(LL p, LL q, LL ans, LL rest) {    if(p <= q) {        return ans + max(rest, q - max(0LL, p));    }    LL l = p - q; int k = Work(l);    if(fac[k - 1] - 1 == l) {        return ans + k - 1 + rest;    }    return min(Solve(p - fac[k-1] + 1, q, ans + k - 1, rest + 1), Solve(p - fac[k] + 1, q, ans + k, rest));}int main(){    fac[0] = 1LL;    for(int i = 1; i <= 62; i++) {        fac[i] = fac[i - 1] * 2;    }    int t; scanf("%d", &t);    while(t--) {        LL q, p; scanf("%lld%lld", &p, &q);        if(p < q) {            printf("%lld\n", q - p);        }        else {            printf("%lld\n", Solve(p, q, 0, 0));        }    }    return 0;}
0 0