2020-2021 ICPC - Gran Premio de Mexico - Repechaje

A. Atsa’s Checkers Board

  • 给定一个 n ∗ m n * m nm大小的矩阵,在该矩阵内放置黑色白色的石头,要保证每个 2 ∗ 2 2 * 2 22的矩阵都有两个黑石头和两个白石头,问有多少种摆放方式
  • 可以发现当有两块颜色相同的石头摆放在一起的时候,整个矩阵的摆放方式就确定了
  • 可以发现第一行至少有一对颜色相同石子相连的方案数是 1 < < m − 2 1 << m - 2 1<<m2
  • 而剩下两种没有颜色相同的石子相连的情况,黑白…和白黑…
  • 取其中一种情况作计算。可以发现当第一行确定为黑白…的时候,第一列的排列方式数就为 1 < < ( n − 1 ) 1 << (n - 1) 1<<(n1)。同理可得第一行确定为白黑…的时候也为 1 < < ( n − 1 ) 1 << (n - 1) 1<<(n1),两者总和即为 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)nn

  • 所以直接从原始矩阵 ( 1 , 0 , 0 , 0... , 0 ) ∗ ( n ∗ n ) 矩 阵 m (1,0,0,0...,0)*(n*n)矩阵^m (1,0,0,0...,0)(nn)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) xpi2 (mod pi)
  • 换过来 x + 2 ≡ p i ≡ 0   ( m o d   p i ) x+2\equiv p_i\equiv0\ (mod\ p_i) x+2pi0 (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 C2n1n, 怎么来的真不知道
#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} cs30360

  • 剩下的 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;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值