AtCoder Beginner Contest 405


A - Is it rated?

点击查看代码
void solve() {
    int R, x;
    std::cin >> R >> x;
    int l = 1600, r = 2999;
    if (x == 2) {
    	l = 1200, r = 2399;
    }

    if (R >= l && R <= r) {
    	std::cout << "Yes\n";
    } else {
    	std::cout << "No\n";
    }
}

B - Not All

题意:判断删除最短的一个后缀,使得剩下的数不同时包含\([1, m]\)的每个数。

\(set\)从前往后记录,如果个数等于\(m\)那么后面的都要删掉。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    int ans = 0;
    std::set<int> s;
    for (int i = 0; i < n; ++ i) {
    	s.insert(a[i]);
    	if (s.size() == m) {
    		ans = n - i;
    		break;
    	}
    }

    std::cout << ans << "\n";
}

C - Sum of Product

题意:给你\(a\)数组,求\(\sum_{i=1}^{n} \sum_{j=i+1}^{n} a_i\times a_j\)

经典结论,答案为\((\sum_{i=1}^{n} a_i)^2 - \sum_{i=1}^{n} a_i^2\)

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    i64 ans = 0, sum = 0;
    for (int i = 0; i < n; ++ i) {
    	i64 x;
    	std::cin >> x;
    	sum += x;
    	ans -= x * x;
    }
    ans += sum * sum;
    std::cout << ans / 2 << "\n";
}

D - Escape Route

题意:大意是有一些出口,你要给每个空地标记方向。使得一直往格子标记的方向走可以到一个距离最近的出口。

多源最短路,一开始把所有出口入队。然后\(bfs\)就行,记录一些每个方向对应要填的符号。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<std::string> s(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> s[i];
    }

    std::vector st(n, std::vector<int>(m));
    std::queue<std::pair<int, int>> q;
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < m; ++ j) {
    		if (s[i][j] == 'E') {
    			q.emplace(i, j);
    			st[i][j] = 1;
    		}
    	}
    }

    const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
    std::string ch = "v<^>";
    while (q.size()) {
    	auto [x, y] = q.front(); q.pop();
    	for (int i = 0; i < 4; ++ i) {
    		int nx = x + dx[i], ny = y + dy[i];
    		if (nx < 0 || nx >= n || ny < 0 || ny >= m || s[nx][ny] == '#' || st[nx][ny]) {
    			continue;
    		}
	    	s[nx][ny] = ch[i];
	    	st[nx][ny] = 1;
	    	q.emplace(nx, ny);
    	}
    }

    for (int i = 0; i < n; ++ i) {
		std::cout << s[i] << "\n";
    }
}

E - Fruit Lineup

题意:苹果、橘子、香蕉、葡萄分别有\(A, B, C, D\)个。把他们排成一排,苹果不能放在香蕉和葡萄后面,橘子不能放在葡萄后面。求不同的组合数。

把它们分成两部分,枚举前部分放了多少个香蕉。
如果前部分放了\(k\)个香蕉,那么后面的方案数容易得出,因为后面只能放剩下的香蕉和葡萄,而它们没有限制,后面的答案是\(C(C - k + D, D)\)。前部分的方案可以先把苹果和香蕉排成一排,因为相同水果没有区间,所以只有一种方案。那么接下来需要用\(B\)个橘子插在里面,每个间隙可以插任意个,那么就是经典插板法,方案数为\(C(A + B + k - 1, B - 1)\)。所以答案为\(C(A + B + k - 1, B - 1) \times C(C - k + D, D)\)
注意特判\(k=0\)的情况。
代码省略取模类。

点击查看代码
struct Comb {
    int n;
    std::vector<Z> _fac;
    std::vector<Z> _invfac;
    std::vector<Z> _inv;
    
    Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
    Comb(int n) : Comb() {
        init(n);
    }
    
    void init(int m) {
        if (m <= n) return;
        _fac.resize(m + 1);
        _invfac.resize(m + 1);
        _inv.resize(m + 1);
        
        for (int i = n + 1; i <= m; i++) {
            _fac[i] = _fac[i - 1] * i;
        }
        _invfac[m] = _fac[m].inv();
        for (int i = m; i > n; i--) {
            _invfac[i - 1] = _invfac[i] * i;
            _inv[i] = _invfac[i] * _fac[i - 1];
        }
        n = m;
    }
    
    Z fac(int m) {
        if (m > n) init(2 * m);
        return _fac[m];
    }
    Z invfac(int m) {
        if (m > n) init(2 * m);
        return _invfac[m];
    }
    Z inv(int m) {
        if (m > n) init(2 * m);
        return _inv[m];
    }
    Z binom(int n, int m) {
        if (n < m || m < 0) return 0;
        return fac(n) * invfac(m) * invfac(n - m);
    }
} comb;

void solve() {
    int a, b, c, d;
    std::cin >> a >> b >> c >> d;
    int n = a + b + c + d;
    Z ans = comb.binom(a + b, a) * comb.binom(c + d, d);
    for (int k = 1; k <= c; ++ k) {
    	ans += comb.binom(a + b + k - 1, b - 1) * comb.binom(c - k + d, d);
    }
    std::cout << ans << "\n";
}

F - Chord Crossing

题意:\(2n\)排成一个圆。有\(m\)条边连接编号为偶数的点。每次询问如果在两个奇数的点加边,会和多少边相交。

其实就是求\([l, r]\)里有多少点往外有边。我们用主席树维护,每个点把所有出边所有的点的位置加一就行,然后询问第\([l, r]\)这些树有多少在区间外面的点。

点击查看代码
#define ls(u) tr[u].lson
#define rs(u) tr[u].rson

const int N = 2e6 + 5;

struct Node {
	int lson, rson;
	int sum;
}tr[N << 5];
int root[N], tot;

void build(int &u, int l, int r) {
	u = ++ tot;
	if (l == r) {
		return;
	}

	int mid = l + r >> 1;
	build(ls(u), l, mid); build(rs(u), mid + 1, r);
}

void modify(int & u, int v, int L, int R, int p, int add) {
	u = ++ tot;
	tr[u] = tr[v];
	tr[u].sum += add;
	if (L == R) {
		return;
	}

	int mid = L + R >> 1;
	if (p <= mid) {
		modify(ls(u), ls(v), L, mid, p, add);
	}

	if (p > mid) {
		modify(rs(u), rs(v), mid + 1, R, p, add);
	}
}

int query(int u, int v, int L, int R, int l, int r) {
	if (l <= L && R <= r) {
		return tr[u].sum - tr[v].sum;
	}

	int mid = L + R >> 1;
	if (r <= mid) {
		return query(ls(u), ls(v), L, mid, l, r);
	} else if (l > mid) {
		return query(rs(u), rs(v), mid + 1, R, l, r);
	}

	return query(ls(u), ls(v), L, mid, l, mid) + query(rs(u), rs(v), mid + 1, R, mid + 1, r);
}

void solve() {
    int n, m;
    std::cin >> n >> m;
   	std::vector<std::vector<int>> adj(2 * n + 1);
   	for (int i = 0; i < m; ++ i) {
   		int u, v;
   		std::cin >> u >> v;
   		adj[u].push_back(v);
   		adj[v].push_back(u);
   	}

   	for (int i = 1; i <= 2 * n; ++ i) {
   		root[i] = root[i - 1];
   		for (auto & v : adj[i]) {
   			modify(root[i], root[i], 1, 2 * n, v, 1);
   		}
   	}

   	int q;
   	std::cin >> q;
   	while (q -- ) {
   		int l, r;
   		std::cin >> l >> r;
   		std::cout << query(root[r], root[l], 1, 2 * n, 1, l) + query(root[r], root[l], 1, 2 * n, r, 2 * n) << "\n";
   	}
}
posted @ 2025-05-10 22:00  maburb  阅读(57)  评论(0)    收藏  举报