A. Atsa’s Checkers Board
- 给定一个 n ∗ m n * m n∗m大小的矩阵,在该矩阵内放置黑色白色的石头,要保证每个 2 ∗ 2 2 * 2 2∗2的矩阵都有两个黑石头和两个白石头,问有多少种摆放方式
- 可以发现当有两块颜色相同的石头摆放在一起的时候,整个矩阵的摆放方式就确定了
- 可以发现第一行至少有一对颜色相同石子相连的方案数是 1 < < m − 2 1 << m - 2 1<<m−2
- 而剩下两种没有颜色相同的石子相连的情况,黑白…和白黑…
- 取其中一种情况作计算。可以发现当第一行确定为黑白…的时候,第一列的排列方式数就为 1 < < ( n − 1 ) 1 << (n - 1) 1<<(n−1)。同理可得第一行确定为白黑…的时候也为 1 < < ( n − 1 ) 1 << (n - 1) 1<<(n−1),两者总和即为 1 < < n 1 << n 1<<n
- 因此总情况数就是 ( 1 < < m ) + ( 1 < < n ) − 2 (1 << m) + (1 << n) - 2 (1<<m)+(1<<n)−2
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 3200;
const int INF = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
inline ll rd() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int main() {
ll n, m;
n = rd();
m = rd();
if (n < 2 || m < 2) {
puts("0");
return 0;
}
printf("%lld\n", (1LL << n) + (1LL << m) - 2);
return 0;
}
C. CLETS Patrols
-
假设一个1*n的矩阵 ( a 1 , a 2 , a 3 . . . a n ) (a_1,a_2,a_3...a_n) (a1,a2,a3...an) , a i a_i ai 表示当前守卫在第 i i i 个点的概率
-
而输入的 n*n 矩阵表示,明显得到以下关系:
( a 1 ′ , a 2 ′ , a 3 ′ , . . . , a n ′ ) = ( a 1 , a 2 , a 3 , . . . , a n ) ∗ 输 入 的 n ∗ n 矩 阵 (a_1',a_2',a_3',...,a_n')=(a_1,a_2,a_3,...,a_n)* 输入的n*n矩阵 (a1′,a2′,a3′,...,an′)=(a1,a2,a3,...,an)∗输入的n∗n矩阵 -
所以直接从原始矩阵 ( 1 , 0 , 0 , 0... , 0 ) ∗ ( n ∗ n ) 矩 阵 m (1,0,0,0...,0)*(n*n)矩阵^m (1,0,0,0...,0)∗(n∗n)矩阵m
-
跑一个矩阵快速幂即可。
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e7 + 10;
const int INF = 0x3f3f3f3f;
inline ll rd() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
ll gcd(ll x, ll y) {
if (y == 0) return x;
return gcd(y, x % y);
}
int n, m;
struct matrix {
double a[202][202];
matrix operator *(const matrix& b) {
matrix c;
/* for (int k = 1;k <= n;++k) {
c.a[1][k] = 0;
for (int i = 1;i <= n;++i) {
c.a[1][k] += this->a[1][i] * b.a[i][k];
}
}
return c;*/
for (int i = 1;i <= n;++i) {
for (int j = 1;j <= n;++j) {
c.a[i][j] = 0;
for (int k = 1;k <= n;++k) {
c.a[i][j] += this->a[i][k] * b.a[k][j];
}
}
}
return c;
}
}mp;
matrix fp(matrix a, int y) {
matrix ans = a;
while (y) {
if (y & 1) ans = ans * a;
a = a * a;
y >>= 1;
}
return ans;
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin >> n >> m;
for (int i = 1;i <= n;++i) {
for (int j = 1;j <= n;++j) {
cin >> mp.a[i][j];
}
}
matrix ans = fp(mp, m - 1);
for (int i = 1;i <= n;++i) {
cout << setprecision(10) << ans.a[1][i] << '\n';
}
return 0;
}
D. Determine the Winner Marshaland
- 有题推得,求的是以下条件:
- x ≡ p i − 2 ( m o d p i ) x\equiv p_i-2\ (mod\ p_i) x≡pi−2 (mod pi)
- 换过来 x + 2 ≡ p i ≡ 0 ( m o d p i ) x+2\equiv p_i\equiv0\ (mod\ p_i) x+2≡pi≡0 (mod pi)
- 所以就对 x + 2 x+2 x+2 进行质因数分解即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ull, ull> pii;
typedef pair<ll, ll>pll;
template<typename T>
inline void rd(T& x) {
int tmp = 1;
char c = getchar();
x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
x *= tmp;
}
const int N = 1e3 + 10;
const int M = 2e7 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ull seed = 31;
ll gcd(ll x, ll y) {
if (y == 0) return x;
return gcd(y, x % y);
}
int head[N], cntE = 0;
struct edge {
int next, to;
}e[M];
void add(int u, int v) {
e[cntE].to = v;
e[cntE].next = head[u];
head[u] = cntE++;
}
int n, m, q;
int prime[N], cnt = 0;
bool isprime[N];
void init() {
for (int i = 2; i <= N - 5; ++i) {
if (!isprime[i]) prime[++cnt] = i;
for (int j = 1; j <= cnt && prime[j] * i <= N - 5; ++j) {
isprime[i * prime[j]] = 1;
if (i % prime[j] == 0) break;
}
}
}
int main() {
#ifdef _DEBUG
FILE* _INPUT = freopen("input.txt", "r", stdin);
// FILE* _OUTPUT = freopen("output.txt", "w", stdout);
#endif
int T = 1, cas = 0;
rd(T);
init();
while (T--) {
rd(n);
n += 2;
vector<int>ans;
while (!(n & 1)) n >>= 1;
for (int i = 2; i <= cnt && prime[i] * prime[i] <= n; ++i) {
if (n % prime[i] == 0) {
ans.push_back(prime[i]);
while (n % prime[i] == 0) n /= prime[i];
}
}
if (n > 1) ans.push_back(n);
if (ans.empty()) puts("-1");
else {
for (int i = 0; i < ans.size(); ++i) {
printf("%d%s", ans[i], i == ans.size() - 1 ? "\n" : " ");
}
}
}
return 0;
}
E. Enterprise Recognition Program
- 给定一个树形图代表一个公司的主从结构,并且公司中有 n n n个员工,老板节点编号为 0 0 0,老板不属于员工
- 操作 m m m次,并且有两种操作
- 第一种操作是给员工 e e e发 v v v元的奖金
- 第二种操作是给员工 e e e及其所有上司发 v v v元的奖金
- 询问 q q q次,并且有两种询问
- 第一种询问是询问员工 x x x有多少奖金
- 第二种询问是询问员工 x x x的下属和员工 x x x共有多少奖金
- 设置一个 e a r n earn earn数组, e a r n [ i ] [ 0 ] earn[i][0] earn[i][0]表示公司用操作一发给员工 i i i的奖金, e a r n [ i ] [ 1 ] earn[i][1] earn[i][1]表示公司用操作二发给员工 i i i的奖金, e a r n [ i ] [ 2 ] earn[i][2] earn[i][2]表示员工 i i i的下属们的总奖金
- 从老板节点开始往下 d f s dfs dfs,从叶子节点往上累加奖金即可
- 以下为两个递推公式, u u u为当前员工, v v v为 u u u的下属
- e a r n [ u ] [ 1 ] + = e a r n [ v ] [ 1 ] ; earn[u][1] += earn[v][1]; earn[u][1]+=earn[v][1];
- e a r n [ u ] [ 2 ] + = e a r n [ v ] [ 0 ] + e a r n [ v ] [ 1 ] + e a r n [ v ] [ 2 ] ; earn[u][2] += earn[v][0] + earn[v][1] + earn[v][2]; earn[u][2]+=earn[v][0]+earn[v][1]+earn[v][2];
- 具体逻辑在代码中体现
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define lowbit(x) ((x) & -(x))
#define endl "\n"
using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e6 + 10, NN = 2e3 + 10, INF = 0x3f3f3f3f, LEN = 20;
const ll MOD = 1e9 + 7;
const ull seed = 31;
const double pi = acos(-1.0), eps = 1e-8;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
struct Edge {
int next, to;
} edge[N];
int num_edge, n, m, q, boss;
int head[N], cha[N];
ll earn[N][3];
void add_edge(int from, int to) {
edge[num_edge].next = head[from];
edge[num_edge].to = to;
head[from] = num_edge++;
}
void init() {
memset(head, -1, sizeof head);
}
void dfs(int u) {
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
dfs(v);
earn[u][1] += earn[v][1];
earn[u][2] += earn[v][0] + earn[v][1] + earn[v][2];
}
}
int main() {
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
n = read(), m = read(), q = read();
init();
for (int i = 1; i <= n; ++i) {
int x = read();
add_edge(x, i);
if (x == 0)
boss = i;
}
for (int i = 1; i <= m; ++i) {
int m = read(), e = read(), v = read();
earn[e][m - 1] += v;
}
dfs(boss);
while (q--) {
int op = read(), x = read();
if (op == 1)
printf("%lld\n", earn[x][0] + earn[x][1]);
else
printf("%lld\n", earn[x][2] + earn[x][1] + earn[x][0]);
}
return 0;
}
G. Goombas Colliding
- 无论怎么撞,最终都会有一辆车子走的是他自己的路程或者别人的路程
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e7 + 10;
const int INF = 0x3f3f3f3f;
inline ll rd() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
ll n, m;
void solve() {
scanf("%lld %lld", &m, &n);
ll ans = 0;
for (int i = 1;i <= n;++i) {
ll p, x;
scanf("%lld %lld", &p, &x);
if (x) ans = max(ans, m - p);
else ans = max(ans, p);
}
printf("%lld\n", ans);
}
int main() {
int T = 1;
while (T--)
solve();
return 0;
}
H. Hamsters Training
- 最后出来的公式是
C
2
n
−
1
n
C_{2n-1}^n
C2n−1n,
怎么来的真不知道
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ull, ull> pii;
typedef pair<ll, ll>pll;
template<typename T>
inline void rd(T& x) {
int tmp = 1;
char c = getchar();
x = 0;
while (c > '9' || c < '0') {
if (c == '-')tmp = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
x *= tmp;
}
const int N = 2e5 + 10;
const int M = 2e7 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ull seed = 31;
ll gcd(ll x, ll y) {
if (y == 0) return x;
return gcd(y, x % y);
}
int n, m, q;
ll fac[N], ifac[N];
ll fp(ll x, ll y) {
ll ans = 1;
while (y) {
if (y & 1) ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
ll C(int x, int y) {
ll ans = fac[x];
ll res = ifac[x - y] * ifac[y] % mod;
ans = ans * res % mod;
return ans;
}
int main() {
#ifdef _DEBUG
FILE* _INPUT = freopen("input.txt", "r", stdin);
// FILE* _OUTPUT = freopen("output.txt", "w", stdout);
#endif
int T = 1, cas = 0;
rd(T);
fac[0] = 1;
for (int i = 1; i <= N - 10; ++i) fac[i] = fac[i - 1] * i % mod;
ifac[N - 10] = fp(fac[N - 10], mod - 2);
for (int i = N - 10; i > 0; --i) ifac[i - 1] = ifac[i] * i % mod;
while (T--) {
rd(n);
ll ans = C(2 * n - 1, n);
printf("%lld\n", ans);
}
return 0;
}
J. Just Turn the Wheels!
-
根据题目意思,首先车轮滚动的距离要大于 s s s ,所以一个首先满足的 t u r n s turns turns 是 s c ∗ 360 30 \frac{s}{c}*\frac{360}{30} cs∗30360
-
剩下的 s 1 = s % c s1=s\%c s1=s%c 的路程:需要满足在 t u r n s turns turns 的情况下还要让两个车轮的边同时平行于地面
-
首先去求共同转动的角度 α \alpha α 能够两车轮的边同时平行于地面: α = 360 ° / g c d ( f , b ) \alpha=360°/gcd(f,b) α=360°/gcd(f,b) , f , b f,b f,b 为输入的车轮顶点数
-
随后求 α \alpha α 和 t u r n s turns turns 的最小公倍数 ,即 θ = l c m ( α , 30 ° ) \theta=lcm(\alpha,30°) θ=lcm(α,30°)
-
对于 s % c s\%c s%c 需要的角度是 β = ⌈ ( s % c ) / c 360 ° ⌉ \beta=\lceil(s\%c)/\ \frac{c}{360°}\rceil β=⌈(s%c)/ 360°c⌉
-
所以最后 s % c s\%c s%c 需要的 t u r n s turns turns 是 ⌈ β θ ⌉ / 30 ° \lceil \frac{\beta}{\theta} \rceil /30° ⌈θβ⌉/30°
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 3200;
const int INF = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
inline ll rd() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int sgn(double x) {
if (fabs(x) < eps)
return 0;
return x < 0 ? -1 : 1;
}
ll gcd(ll x, ll y) {
if (!y) return x;
return gcd(y, x % y);
}
ll c, f, b, s;
int main() {
int T;scanf("%d", &T);
while (T--) {
scanf("%lld %lld %lld %lld", &c, &f, &b, &s);
ll ans = 12LL * (s / c);
s %= c;
ll tmp1 = gcd(f, b);
ll t = gcd(360, tmp1);
ll x = 1LL * 360 / t;
ll y = 30 ;
ll tmp2 = x * y / gcd(x, y);
ll res = (s * 360 / c);
if (s * 360 % c != 0) ++res;
res = res / tmp2 + (res % tmp2 != 0);
res = res * tmp2 / 30;
ans += res;
printf("%lld\n", ans);
}
}
K. Kitchen Waste
- 有 n n n个面包, m m m口锅,每口锅中都装了一定体积的汤,要将汤淋在面包上,面包也有体积,一体积汤能淋一体积面包
- 一次淋面包的操作必须要将整个面包都淋上汤,若锅中剩余汤的体积不足以将整个面包都淋上,则将这个锅中的汤都倒掉
- 签到题,根据题意直接模拟即可
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e7 + 10;
const int INF = 0x3f3f3f3f;
inline ll read() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int n, m;
int a[N], b[N];
int main() {
n = read();
m = read();
for (int i = 1; i <= n; ++i)
a[i] = read();
for (int i = 1; i <= m; ++i)
b[i] = read();
int pos = 1;
for (int i = 1; i <= m; ++i) {
while (b[i] >= a[pos]) {
b[i] -= a[pos];
++pos;
if (pos > n)
break;
}
if (pos > n)
break;
}
int ans = 0;
for (int i = 1; i <= m; ++i)
ans += b[i];
printf("%d\n", ans);
return 0;
}
L. Lets Count Factors
- 题意很明确,求 A , B A,B A,B 的共同质因数
- 这题稍有不慎就会超时,下欧拉筛的范围控制到 1 0 7 \sqrt{10^7} 107 就可以了
- 对于共同质因数的标记,使用 u n o r d e r e d _ m a p unordered\_map unordered_map 就万无一失了
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 3200;
const int INF = 0x3f3f3f3f;
inline ll rd() {
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int cnt;
int vis[N], pri[N];
void Euler(int n) {
for (int i = 2; i <= n; i++) {
if (!vis[i])
pri[++cnt] = i;
for (int j = 1; j <= cnt; j++) {
if (i * pri[j] > n)
break;
vis[i * pri[j]] = true;
if (i % pri[j] == 0)
break;
}
}
}
unordered_map<int, bool>visn;
void cal(int x) {
for (int i = 1;i <= cnt;++i) {
if (x % pri[i] == 0) {
visn[pri[i]] = 1;
while (x % pri[i] == 0) x /= pri[i];
}
}
if (x > 1) visn[x] = 1;
}
void solve() {
int a = (int)rd(), b = (int)rd();
visn.clear();
cal(a);
cal(b);
printf("%d\n", visn.size());
}
int main() {
int T = (int)rd();
Euler(N);
while (T--)
solve();
return 0;
}