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)的方案數。
#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|1
using 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
日狗,看了好久不懂題意?
題意:
意思是讓你找到若干個子集,使得
#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|1
using 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|1
using 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;
}