2020-2021 ACM-ICPC, Asia Seoul Regional Contest

B. Commemorative Dice

简单题。要你求出摇色子获胜的最大概率是多少。两个色子的点数和都为 21 21 21,若摇出的色子点数大于对方,则算获胜。观察可得无论挑哪个色子获胜的概率都是相同的。
利用 m a p map map会自动排序的特性 O ( N 2 ) O(N^2) O(N2)遍历即可。利用了概率论的基础知识。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e5 + 10;
map<int, int> mp1, mp2;
int a[N], b[N];
int ans;
int gcd(int x, int y) {
    
    
    return x == 0 ? y : gcd(y % x, x);
}
int main() {
    
    
    for (int i = 1; i <= 6; ++i) {
    
    
        scanf("%d", &a[i]);
        ++mp1[a[i]];
    }

    for (int i = 1; i <= 6; ++i) {
    
    
        scanf("%d", &b[i]);
        mp2[b[i]]++;
    }
    for (auto it : mp1) {
    
    
        int number = it.first;
        int sum = it.second;
        int win = 0;
        for (auto itt : mp2) {
    
    
            int number2 = itt.first;
            int sum2 = itt.second;
            if (number > number2)
                win += sum2;
        }
        if (win == 0)
            continue;
        ans += sum * win;
    }
    int x = gcd(ans, 36);
    printf("%d/%d\n", ans / x, 36 / x);
    return 0;
}

C. Dessert Café

给定一个有 n n n个节点的树,树上有 k k k个特殊节点,问有多少个节点到达某个特殊节点的距离小于该节点到其他所有特殊节点的距离。由于树上两点间的路径是固定的,可以观察发现,只要是处于两个特殊节点路径上的节点都符合题目的要求,那么爆搜遍历整棵树即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e6 + 10;
struct Edge {
    
    
    int next, to, dis;
} edge[N];
set<int> st;
vector<int> vec;
int n, k, num_edge;
int head[N];
bool vis[N];
void add_edge(int from, int to, int dis) {
    
    
    edge[num_edge].next = head[from];
    edge[num_edge].to = to;
    edge[num_edge].dis = dis;
    head[from] = num_edge++;
}
void init() {
    
    
    memset(head, -1, sizeof head);
}
bool dfs(int u, int fa) {
    
    
    bool flag = false;
    for (int i = head[u]; i != -1; i = edge[i].next) {
    
    
        int v = edge[i].to;
        if (v == fa)
            continue;
        flag = flag | dfs(v, u);
    }
    if (flag || vis[u])
        st.insert(u);
    if (vis[u] || flag)
        return true;
    else
        return false;
}
int main() {
    
    
    scanf("%d%d", &n, &k);
    init();
    for (int i = 1; i <= n - 1; ++i) {
    
    
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add_edge(u, v, w);
        add_edge(v, u, w);
    }
    int x = -1;
    for (int i = 1; i <= k; ++i) {
    
    
        scanf("%d", &x);
        vis[x] = true;
    }
    dfs(x, -1);
    printf("%d\n", st.size());
    return 0;
}

E. Imprecise Computer

相差1给出的结果可能有误,意思就是说每个数每轮的得分差距只和左右两边的数有关,通过l数组和r数组来标记和左右相邻数字的胜负情况,1表示胜利,0表示失败。需要注意的是第一个数的l一定为0,最后一个数的r一定为0。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 10;
const ll NN = 1e9 + 1;
const int INF = 0x3f3f3f3f;
int r[N], l[N];
int l2[N], r2[N];
int n;
int main() {
    
    
	scanf("%d", &n);
	int flag = 1;
	for (int i = 1; i <= n; ++i) {
    
    
		int num; scanf("%d", &num);
		if (!flag) continue;
		if (i == 1) {
    
    
			l[i] = 0;
			r[i] = num;
			if (r[i] >= 2) flag = 0;
		}
		else if (i == n) {
    
    
			l2[i] = r2[i - 1] ^ 1;
			l[i] = r[i - 1] ^ 1;
			r[i] = 0;
			r2[i] = 0;
			if (abs(l[i] + r[i] - l2[i] - r2[i]) != num) flag = 0;
		}
		else {
    
    
			l2[i] = r2[i - 1] ^ 1;
			l[i] = r[i - 1] ^ 1;
			if (l2[i] == l[i]) {
    
    
				if (num >= 2) flag = 0;
				else if (num == 0) {
    
    
					r2[i] = r[i] = 0;
				}
				else {
    
    
					r[i] = 1;
					r2[i] = 0;
				}
			}
			else {
    
    
				if (num > 2) flag = 0;
				else if (num == 0) {
    
    
					r[i] = l2[i];
					r2[i] = l[i];
				}
				else if (num == 1)
					r[i] = r2[i] = 0;
				else {
    
    
					r[i] = l[i];
					r2[i] = l2[i];
				}
			}
		}
	}
	if (flag) printf("YES\n");
	else printf("NO\n");
	return 0;
}

G. Mobile Robot

注意有两种情况,可以从前往后排,也有可能从后往前排,另外保持绝对值最小就行。用double输出会wa,可能有精度问题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6 + 10;
const ll NN = 1e9 + 1;
const int INF = 0x3f3f3f3f;
ll n, k;
ll a[N], b[N];
int main() {
    
    
	scanf("%lld %lld", &n, &k);
	ll temp1 = 0, temp2 = 0;
	for (int i = 1; i <= n; ++i) {
    
    
		ll num; scanf("%lld", &num);
		a[i] = temp1 - num;
		b[i] = temp2 - num;
		temp1 += k;
		temp2 -= k;
	}
	sort(a + 1, a + 1 + n);
	sort(b + 1, b + 1 + n);
	ll ans = min((a[n] - a[1]), (b[n] - b[1]));
	if ((ans & 1)) printf("%lld.5\n", ans / 2);
	else printf("%lld.0\n", ans / 2);
	return 0;
}

H. Needle

  • 根据题目要求,首先可以得出需要满足
    y 2 − y 1 x 2 − x 1 = y 3 − y 2 x 3 − x 2 \frac{y_2-y_1}{x_2-x_1}=\frac{y_3-y_2}{x_3-x_2} x2x1y2y1=x3x2y3y2
    化简得 x 1 + x 3 = 2 ∗ x 2 x_1+x_3=2*x_2 x1+x3=2x2
  • 暴力的想法实现是 O ( n 2 ) O(n^2) O(n2) ,不现实,现考虑另一种形式
  • 假设多项式 A ( x ) = ∑ a i x p i A(x)=\sum a_ix^{p_i} A(x)=aixpi ,假设上述数据化简式为指数
  • 设 多项式 A ( x ) A(x) A(x)为包含所有 x 1 x_1 x1 为指数的多项式, B ( x ) B(x) B(x) 为包含所有 x 3 x_3 x3 为指数的多项式
  • 所以求多项式 A ( x ) ∗ B ( x ) A(x)*B(x) A(x)B(x) 中的指数是 x 2 ∗ 2 x_2*2 x22 的系数和
  • 关于多项式乘法直接用 F F T FFT FFT 即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uii;
typedef pair<int, int> pii;
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;
}
ll gcd(ll x, ll y) {
    
    
	if (y == 0) return x;
	return gcd(y, x % y);
}
const int N = 1e6 + 10;
const int M = 1e7 + 10;
const int mod = 998244353;
const ull seed = 31;
const double eps = 1e-3;
int sgn(double x) {
    
    
	if (fabs(x) <= eps) return 0;
	if (x > 0) return 1;
	return -1;
}
int head[N], cntE = 0;
struct edge {
    
    
	int next, to;
	double w;
}e[M];
void add(int u, int v, double w = 0) {
    
    
	e[cntE].to = v;
	e[cntE].next = head[u];
	e[cntE].w = w;
	head[u] = cntE++;
}
int n, m, k;
const double pi = acos(-1.0);
struct complexx {
    
    
	double x, y;
	complexx(double x = 0, double y = 0) :x(x), y(y) {
    
    }
	complexx friend operator + (complexx a, complexx b) {
    
     return complexx(a.x + b.x, a.y + b.y); }
	complexx friend operator - (complexx a, complexx b) {
    
     return complexx(a.x - b.x, a.y - b.y); }
	complexx friend operator * (complexx a, complexx b) {
    
     return complexx(a.x * b.x - a.y * b.y, a.y * b.x + a.x * b.y); }
}a[N], c[N];
int rev[N];
int b[N], sum[N];
void fft(complexx y[], int len, int on) {
    
    
	for (int i = 0; i < len; i++) {
    
    
		if (i < rev[i]) swap(y[i], y[rev[i]]);
	}
	for (int h = 2; h <= len; h <<= 1) {
    
    
		complexx wn(cos(-on * 2 * pi / h), sin(-on * 2 * pi / h));
		for (int j = 0; j < len; j += h) {
    
    
			complexx w(1, 0);
			for (int k = j; k < j + h / 2; k++) {
    
    
				complexx u = y[k];
				complexx t = w * y[k + h / 2];
				y[k] = u + t;
				y[k + h / 2] = u - t;
				w = w * wn;
			}
		}
	}
	if (on == -1) {
    
    
		for (int i = 0; i < len; i++) {
    
    
			y[i].x /= len;
		}
	}
}
int main() {
    
    
#ifdef _DEBUG
	FILE* _INPUT = freopen("input.txt", "r", stdin);
	//	FILE* _OUTPUT = freopen("output.txt", "w", stdout);
#endif // !_DEBUG
	int cas = 0, T = 1;
	//	rd(T);
	while (T--) {
    
    
//	while (~scanf("%d", &n)) {
    
    
		int m1 = 0, m3 = 0;
		rd(n);
		for (int i = 1; i <= n; ++i) {
    
    
			int x; rd(x); x += 3e4;
			a[x].x += 1;
			m1 = max(m1, x);
		}
		rd(k);
		for (int i = 1; i <= k; ++i) rd(b[i]), b[i] += 3e4;
		rd(m);
		for (int i = 1; i <= m; ++i) {
    
    
			int x; rd(x); x += 3e4;
			c[x].x += 1;
			m3 = max(m3, x);
		}
		int len = 1, l = 0;
		for (; len <= m1 + m3; len <<= 1, l++);
		for (int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
		fft(a, len, 1);
		fft(c, len, 1);
		for (int i = 0; i < len; i++)
			a[i] = a[i] * c[i];
		fft(a, len, -1);
		for (int i = 0; i <= len; ++i) sum[i] = (int)(a[i].x + 0.5);
		ll ans = 0;
		for (int i = 1; i <= k; ++i) {
    
    		
			ans += sum[b[i] * 2];
		}
		printf("%lld\n", ans);
	}
	return 0;
}


J. Switches

  • 根据题目要求,每次输出 n n n 行,对应各种操作后结果只有第 i i i 盏灯开启
  • 假设对应的开关行为数组为 A A A ,是一个 1 × n 1×n 1×n 的矩阵
  • 假设题目给出的 n × n n×n n×n 的矩阵为 B B B
  • 假设最终的结果矩阵为 C C C ,是 1 × n 1×n 1×n 的矩阵
  • 显然满足对于每个 i i i , A ∗ B = C A*B=C AB=C
  • 其中对于每个 i i i C C C 矩阵为已知,所以转为 A = C ∗ B − 1 A=C*B^{-1} A=CB1
  • 所以就要求出 B B B 的逆矩阵,若 B B B 不可逆则无解
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uii;
typedef pair<int, int> pii;
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;
}
ll gcd(ll x, ll y) {
    
    
	if (y == 0) return x;
	return gcd(y, x % y);
}
const int N = 5e2 + 10;
const int M = 1e7 + 10;
const int mod = 998244353;
const ull seed = 31;
const double eps = 1e-10;
int sgn(double x) {
    
    
	if (fabs(x) <= eps) return 0;
	if (x > 0) return 1;
	return -1;
}
int head[N], cntE = 0;
struct edge {
    
    
	int next, to;
	double w;
}e[M];
void add(int u, int v, double w = 0) {
    
    
	e[cntE].to = v;
	e[cntE].next = head[u];
	e[cntE].w = w;
	head[u] = cntE++;
}
int n, m, k;
bitset<N << 1>a[N];
int Gauss_rev(int n) {
    
    
    for (int i = 1; i <= n; i++) {
    
    
        for (int j = i; j <= n; j++) {
    
    
            if (a[j][i]) {
    
    
                swap(a[i], a[j]);
                break;
            }
        }
        if (!a[i][i]) return 0;
        for (int j = 1; j <= n; j++) {
    
    
            if (a[j][i] && j != i) {
    
    
                a[j] ^= a[i];
            }
        }
    }
    return 1;
}
struct matrix {
    
    
    bitset<N>r[N], c[N];
    void init() {
    
    
        for (int i = 1; i <= n; i++) {
    
    
            r[i].reset();
        }
        for (int i = 1; i <= n; i++) {
    
    
            c[i].reset();
        }
    }
    matrix operator*(const matrix& B) {
    
    
        matrix ans;
        ans.init();
        for (int i = 1; i <= 1; i++) {
    
    
            for (int j = 1; j <= n; j++) {
    
    
                ans.r[i][j] = ans.c[j][i] = (((r[i] & B.c[j]).count()) & 1);
            }
        }
        return ans;
    }
};
int main() {
    
    
#ifdef _DEBUG
	FILE* _INPUT = freopen("input.txt", "r", stdin);
	//	FILE* _OUTPUT = freopen("output.txt", "w", stdout);
#endif // !_DEBUG
	int cas = 0, T = 1;
//	rd(T);
	while (T--) {
    
    
//	while (~scanf("%d",&n)) {
    
    
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
    
    
            for (int j = 1; j <= n; j++) {
    
    
                int x; rd(x);
                if(x) a[i][j] = 1;
            }
            a[i][i + n] = 1;
        }
        if (!Gauss_rev(n)) {
    
    
            puts("-1");
        }
        else {
    
    
            matrix B; B.init();
            for (int i = 1; i <= n; i++) {
    
    
                for (int j = 1; j <= n; j++) {
    
    
                    B.r[i][j] = B.c[j][i] = a[i][j + n];
                }
            }
            for (int i = 1; i <= n; ++i) {
    
    
                matrix ans;
                ans.init();
                ans.r[1][i] = 1;
                ans.c[i][1] = 1;
                ans = ans * B;
                bool first = true;
                for (int i = 1; i <= n; ++i) {
    
    
                    if (!ans.r[1][i]) continue;
                    if (first) first = false;
                    else printf(" ");
                    printf("%d", i);
                }
                puts("");
            }
        }
        return 0;
	}
	return 0;
}


L. Two Buildings

  • 决策单调性,待补

猜你喜欢

转载自blog.csdn.net/bloom_er/article/details/114437910