• AtCoder Beginner Contest 250 赛时记录


    赛时发现 G 和 Ex 是原题而且自己都做过,直接贺了过来/kx

    F 因为是算几只知道做法不是很会写。

    rk23 赢麻了/kx,大概是最高名次了/kx

    A - Adjacent Squares

    简单特判。

    signed main() {
    	int H = read(), W = read();
    	int R = read(), C = read();
    	int ans = 0;
    	ans += (R > 1);
    	ans += (C > 1);
    	ans += (R < H);
    	ans += (C < W);
    	cout << ans << "\n";
    	return 0;
    }
    

    B - Enlarged Checker Board

    简单模拟。

    int f[1010][1010];
    signed main() {
    	int n = read(), a = read(), b = read();
    	for(int i = 1; i <= n; ++i) 
    		for(int j = 1; j <= n; ++j) 
    			for(int l = 1; l <= a; ++l) 
    				for(int r = 1; r <= b; ++r) 
    					if((i + j) & 1) f[(i - 1) * a + l][(j - 1) * b + r] = 1;
    	for(int i = 1; i <= n * a; ++i) {
    		for(int j = 1; j <= n * b; ++j) 
    			cout << (f[i][j] == 1 ? '#' : '.');
    		puts("");
    	}
    	return 0;
    }
    

    C - Adjacent Swaps

    数组的简单应用。

    signed main() {
    	int n = read(), Q = read();
    	vector<int> a(n + 2), pre(n + 2);
    	for(int i = 1; i <= n; ++i) a[i] = i, pre[i] = i;
    	for(int i = 1; i <= Q; ++i) {
    		int x = read(), u, v;
    		if(pre[x] == n) {
    			u = pre[x], v = pre[x] - 1;
    		} else {
    			u = pre[x], v = pre[x] + 1;
    		}
    		swap(a[u], a[v]);
    		pre[a[u]] = u, pre[a[v]] = v;
    	}
    	for(int i = 1; i <= n; ++i) cout << a[i] << " "; puts("");
    	return 0;
    }
    

    D - 250-like Number

    一开始被题意坑了,以为 \(q\) 可以不是素数。

    考虑暴力枚举素数。

    因为 \(n \le 10^{18}\)\(p < q\),所以 \(p < 10^5\)

    对于 \(q\) 的话只需要枚举 \(10^6\) 内的素数即可。

    然后线筛一下 \(10^6\) 以内的所有素数暴力枚举就好了。

    反正跑起来挺快的,复杂度大概是 \(10^5\) 带个 \(\log\) 这种级别。

    int n, ans = 0;
    int prim[MAXN], Cnt = 0;
    bool vis[MAXN];
    void Init(int M) {
    	for(int i = 2; i <= M; ++i) {
    		if(!vis[i]) prim[++Cnt] = i;
    		for(int j = 1; j <= Cnt && i * prim[j] <= M; ++j) {
    			vis[i * prim[j]] = true;
    			if(i % prim[j] == 0) break;
    		}
    	}
    }
    void Print(__int128 x){
    	if(x > 9) Print(x / 10);
    	putchar(x % 10 + '0');
    }
    signed main() {
    	Init(1000000); n = read();
    	for(int i = 1; i <= Cnt; ++i) {
    		int p = prim[i];
    		for(int k = i + 1; k <= Cnt; ++k) {
    			int j = prim[k];
    			__int128 x = (__int128)p * j * j * j, y = n;
    			if(x > y) break;
    			ans ++;
    		}
    	}
    	cout << ans << "\n";
    	return 0;
    }
    

    E - Prefix Equality

    一眼题。

    考虑处理出某个数在另一个数组第一次出现的位置。

    可以先离散化。

    \(a\) 数组为例,处理出 \(a\) 数组的每一项在 \(b\) 数组中第一次出现的位置,然后建立线段树。

    对于每次查询 \(x,y\),就是查询 \(a\) 数组的前 \(x\) 项中是不是所有元素都在 \(b\) 的前 \(y\) 项中出现,即判断 \(1 \sim x\) 中的最大值是不是 \(\le y\)

    然后对 \(b\) 也类似处理一下即可。

    int n, Q;
    int a[MAXN], b[MAXN];
    int date[MAXN << 1], Cnt = 0, top = 0;
    int vis[MAXN << 1], fir[MAXN << 1];
    int Vis[MAXN << 1], Fir[MAXN << 1];
    
    struct Seg {
    #define lson i << 1
    #define rson i << 1 | 1
    	int Max[MAXN << 2];
    	void Push_up(int i) { Max[i] = max(Max[lson], Max[rson]); }
    	void Build(int i, int l, int r, int k) {
    		if(l == r) { Max[i] = k ? Vis[l] : vis[l]; return ;}
    		int mid = (l + r) >> 1;
    		Build(lson, l, mid, k), Build(rson, mid + 1, r, k);
    		Push_up(i);
    	}
    	int Query(int i, int l, int r, int L, int R) {
    		if(L <= l && r <= R) return Max[i];
    		int mid = (l + r) >> 1, ans = 0;
    		if(mid >= L) ans = max(ans, Query(lson, l, mid, L, R));
    		if(mid < R) ans = max(ans, Query(rson, mid + 1, r, L, R));
    		return ans;
    	}
    }seg[2];
    
    signed main() {
    	n = read();
    	for(int i = 1; i <= n; ++i) a[i] = read();
    	for(int i = 1; i <= n; ++i) b[i] = read();
    	for(int i = 1; i <= n; ++i) date[++top] = a[i], date[++top] = b[i];
    	sort(date + 1, date + top + 1);
    	Cnt = unique(date + 1, date + top + 1) - date - 1;
    	for(int i = 1; i <= n; ++i) a[i] = lower_bound(date + 1, date + Cnt + 1, a[i]) - date;
    	for(int i = 1; i <= n; ++i) b[i] = lower_bound(date + 1, date + Cnt + 1, b[i]) - date;
    	for(int i = 1; i <= Cnt; ++i) fir[i] = n + 1, Fir[i] = n + 1;
    	for(int i = n; i >= 1; --i) fir[b[i]] = i, Fir[a[i]] = i;
    	for(int i = n; i >= 1; --i) vis[i] = fir[a[i]], Vis[i] = Fir[b[i]];
    //	for(int i = 1; i <= n; ++i) cout << vis[i] << " "; puts("");
    	Q = read();
    	seg[0].Build(1, 1, n, 0);
    	seg[1].Build(1, 1, n, 1);
    	for(int i = 1; i <= Q; ++i) {
    		int x = read(), y = read();
    		int res1 = seg[0].Query(1, 1, n, 1, x);
    		int res2 = seg[1].Query(1, 1, n, 1, y);
    //		cout << x << " " << y << "\n";
    		if(res1 <= y && res2 <= x) puts("Yes");
    		else puts("No");
    	}
    	return 0;
    }
    

    F - One Fourth

    计算几何题/px

    考虑固定一个点,然后找到面积是最接近总面积 \(\frac{1}{4}\)\(\frac{3}{4}\) 的地方,然后类似于双指针同时顺时针或者逆时针移动这些点即可,对所有结果取一个最优值。

    G - Stonks

    原题:CF865D

    好像是简单反悔贪心。

    就是从前向后扫,拿一个小根堆维护我们可能在哪些天买(具体天数不需要,只需要价格

    如果发现当前这个值 \(p_i\) 大于堆顶 \(p_j\),那么我们可以在第 \(j\) 天买入第 \(i\) 天卖出,因此有一个 \(p_i - p_j\) 的贡献。然后我们把堆顶元素弹出,加入 \(p_i\) 即可。

    如果后面有 \(p_k > p_i\),那么同样操作时会得到 \(p_k - p_i\) 的贡献,两次的贡献和相当于 \(p_k - p_j\),因此这么反悔贪心是对的。

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int n, ans = 0;
    priority_queue<int, vector<int>, greater<int> > q;
    signed main()
    {
    	cin >> n;
    	for(int i = 1, x; i <= n; ++i) {
    		cin >> x;
    		if(!q.empty() && q.top() < x) ans += x - q.top(), q.pop(), q.push(x);
    		q.push(x);
    	}
    	printf("%lld\n", ans);
    	return 0;
    }
    

    Ex - Trespassing Takahashi

    原题:CF1253F

    和原题唯一的区别就是最后的判断。

    可以去看我在洛谷写的题解:link

    这里还有一个在博客园的链接:link

    /*
    思路极其鬼畜:
    1、最短路
    2、生成树
    3、倍增+LCA
    4、查询 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    //#include<time.h>
    #define LL long long
    #define int long long
    #define orz cout<<"lkp AK IOI!"<<endl
    
    using namespace std;
    const int MAXN = 4e5+5;
    const int MAXM = 6e5+5;
    const int INF = 1e9+7;
    const int mod = 1e9+7;
    
    struct edge{
    	int from, to, w, nxt;
    }e[MAXM << 2], E[MAXM], E2[MAXM << 1];
    int head[MAXN], num_edge = 0;
    int Head[MAXN], Num_edge = 0;
    
    struct node{
    	int bh, val;
    	bool operator < (const node &b) const { return val > b.val; }
    };
    
    int n, m, k, Q, cnt;
    int dis[MAXN], fa[MAXN], f[MAXN][22], dep[MAXN], maxm[MAXN][22];
    bool vis[MAXN];
    priority_queue<node> q;
    
    int read(){
    	int s = 0, f = 0;
    	char ch = getchar();
    	while(!isdigit(ch))  f |= (ch == '-'), ch = getchar();
    	while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0' , ch = getchar();
    	return f ? -s : s;
    }
    
    bool cmp(edge x, edge y){ return x.w < y.w; }
    void add_edge(int from, int to, int w){ e[++num_edge] = (edge){from, to, w, head[from]}, head[from] = num_edge; }
    void Add_edge(int from, int to, int w){ E2[++Num_edge] = (edge){from, to, w, Head[from]}, Head[from] = Num_edge; }
    int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    
    void dij(){
    	memset(dis, 0x3f, sizeof dis);
    	dis[0] = 0;
    	q.push((node){0, 0});
    	while(!q.empty()){
    		node u = q.top(); q.pop();
    		if(vis[u.bh]) continue;
    		vis[u.bh] = true;
    		for(int i = head[u.bh]; i; i = e[i].nxt){
    			int v = e[i].to;
    			if(dis[v] > dis[u.bh] + e[i].w){
    				dis[v] = dis[u.bh] + e[i].w;
    				if(!vis[v]) q.push((node){v, dis[v]});
    			}
    		}
    	}
    }
    
    void kruskal(){
    	for(int i = 1; i <= n; ++i) fa[i] = i;//重置父亲 
    	for(int i = 1; i <= m; ++i){
    		int uf = find(E[i].from), vf = find(E[i].to);
    		if(uf != vf){
    			fa[vf] = uf;
    			Add_edge(E[i].from, E[i].to, E[i].w), Add_edge(E[i].to, E[i].from, E[i].w);//建出最小生成树来 
    			cnt++;
    			if(cnt == n - 1) return ;//如果建了n - 1条边,就结束 
    		}
    	}
    }
    
    void dfs(int u, int fa){//dfs预处理lca 
    	f[u][0] = fa;
    	for(int i = Head[u]; i; i = E2[i].nxt){
    		int v = E2[i].to;
    		if(v == fa) continue;
    		dep[v] = dep[u] + 1;
    		maxm[v][0] = E2[i].w;
    		dfs(v, u);
    	}
    }
    
    void init(){//预处理lca 
    	for(int i = 1; i <= 20; ++i)
    		for(int j = 1; j <= n; ++j)
    			f[j][i] = f[f[j][i - 1]][i - 1],
    			maxm[j][i] = max(maxm[j][i - 1], maxm[f[j][i - 1]][i - 1]);
    }
    
    int get_max(int x, int y){
    	int ans = 0;
    	if(dep[x] < dep[y]) swap(x, y);
    	for(int i = 20; i >= 0; --i){
    		if(dep[f[x][i]] < dep[y]) continue;
    		ans = max(ans, maxm[x][i]);
    		x = f[x][i];
    	}
    	if(x == y) return ans;
    	for(int i = 20; i >= 0; --i){
    		if(f[x][i] == f[y][i]) continue;
    		ans = max(ans, max(maxm[x][i], maxm[y][i]));
    		x = f[x][i], y = f[y][i];
    	}
    	ans = max(ans, max(maxm[x][0], maxm[y][0]));
    	return ans;
    }
    
    signed main() {
    	n = read(), m = read(), k = read();
    	for(int i = 1, u, v, w; i <= m; ++i){
    		u = read(), v = read(), w = read();
    		add_edge(u, v, w), add_edge(v, u, w);
    		E[i].from = u, E[i].to = v, E[i].w = w;
    	}
    	for(int i = 1; i <= k; ++i) add_edge(0, i, 0), add_edge(i, 0, 0);    
    	dij();
    	for(int i = 1; i <= m; ++i) E[i].w += dis[E[i].from] + dis[E[i].to];
    	sort(E + 1, E + m + 1, cmp); 
    	kruskal();	dep[1] = 1;	dfs(1, -1);	init();	Q = read();
    	for(int i = 1, u, v, t; i <= Q; ++i){
    		u = read(), v = read(), t = read();
    		int res = get_max(u, v);
    		if(res <= t) puts("Yes");
    		else puts("No");
    	}
    	return 0;
    }
    
  • 相关阅读:
    题解 P4111 [HEOI2015]小 Z 的房间
    题解 P3317 [SDOI2014]重建
    题解 P4336 [SHOI2016]黑暗前的幻想乡
    NOIP 模拟 7 考试总结
    NOIP 模拟 7 回家
    NOIP 模拟 7 寿司
    MySQL: 多表查询
    MySQL:设计演员与角色表(多对多)
    MySQL:设计省&市表 (一对多)
    MySQL:多表关系设计(一对多 / 多对多 / 一对一)
  • 原文地址:https://www.cnblogs.com/Silymtics/p/ABC250.html
Copyright © 2020-2023  润新知