• Codeforces Round #788 (Div. 2) VP 记录


    蛤蛤我就是那个 VP 只过三题的垃圾。

    D 据说可以 OEIS,然后因为读错题寄了半小时,OEIS 又翻了半小时没找到。最后几分钟才发现是个傻逼规律。

    E 也不是很难,何队一眼秒了。

    A. Prof. Slim

    发现只能交换正负号。那就把所有负号放在前面看看是不是一个不降序列即可。

    #include<bits/stdc++.h>
    #define LL long long 
    //#define int long long
    #define orz cout << "tyy YYDS!!!\n"
    using namespace std;
    const int MAXN = 2e5 + 10;
    const int INF = 1e9 + 7;
    const int mod = 998244353;
    
    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 ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    void Main() {
    	int n = read();
    	vector<int> a(n + 1);
    	int cnt = 0;
    	for(int i = 1; i <= n; ++i) {
    		a[i] = read();
    		cnt += a[i] < 0;
    	}
    	for(int i = 1; i <= n; ++i) {
    		if(i <= cnt) a[i] = - abs(a[i]);
    		else a[i] = abs(a[i]);
    	}
    	for(int i = 2; i <= n; ++i) {
    		if(a[i] < a[i - 1]) {
    			return puts("NO"), void();
    		}
    	}
    	puts("YES");
    }
    
    signed main() {
    	int T = read();
    	while(T--) Main();
    	return 0;
    }
    

    B. Dorms War

    标记一下特殊点。

    从前往后枚举每一个字符。

    随便用一个值 \(sc\) 来维护这个特殊点以及因为在他前面而被删掉的点

    因此记录一下上一个特殊点的位置 \(lst\)

    设当前枚举到的 \(i\) 为特殊点。

    那么因为在这个点前面而被删掉的点有 \(\max (0, sc - 2len) + len\) 个,其中 \(len = i - lst\)

    就是考虑这两个特殊点同时删,后面这个特殊点删到第 \(len\) 次的时候就把前面那个特殊点删掉了,此时前面那个特殊点也删了 \(len\) 次,那么剩下的就可以让当前这个特殊点删了。

    #include<bits/stdc++.h>
    #define LL long long 
    //#define int long long
    #define orz cout << "tyy YYDS!!!\n"
    using namespace std;
    const int MAXN = 2e5 + 10;
    const int INF = 1e9 + 7;
    const int mod = 998244353;
    
    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 ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    int n, K, lst;
    char s[MAXN];
    char t[30];
    bool vis[30];
    int stc[MAXN], sc = 0;
    
    void Main() {
    	n = read(), sc = lst = 0;
    	cin >> s + 1;
    	K = read();
    	memset(vis, false, sizeof vis);
    	for(int i = 1; i <= K; ++i) scanf("%c", &t[i]), getchar(), vis[t[i] - 'a'] = true;
    //	for(int i = 1; i <= K; ++i) cout << t[i] << " "; puts("");
    //	cout << "check: " << vis['y' - 'a'] << "\n";
    	while(n && !vis[s[n] - 'a']) --n; 
    	for(int i = 1; i <= n; ++i) {
    		int c = s[i] - 'a';
    		if(!vis[c]) {
    			++sc;
    		} else {
    			if(lst) {
    				int len = i - lst;
    				sc = max(0, sc - 2 * len) + len;
    			}
    			lst = i;
    			++sc;
    		}
    	}
    	sc = max(sc - 1, 0);
    	cout << sc << "\n";
    //	cout << "ans: " << n << " " << sc << "\n";
    }
    
    signed main() {
    	int T = read();
    	while(T--) Main();
    	return 0;
    }
    

    C. Where is the Pizza?

    看到两个排列,果断考虑转化成图论。

    \(a_i\)\(b_i\) 连边。

    最终的情况一定是若干个环。

    发现只要确定了环上的一个点,剩下的都能确定。

    也就是说,如果一个环上的点数 \(>2\) 且没有已经确定的点,那么这个环会对方案数贡献一个 \(\times 2\)

    #include<bits/stdc++.h>
    #define LL long long 
    //#define int long long
    #define orz cout << "tyy YYDS!!!\n"
    using namespace std;
    const int MAXN = 2e5 + 10;
    const int INF = 1e9 + 7;
    const int mod = 1e9 + 7;
    
    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 ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    int fa[MAXN];
    int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    
    void Main() {
    	int n = read();
    	vector<int> a(n + 1), b(n + 1), d(n + 1), siz(n + 1);
    	vector<int> vis(n + 1, 0);
    	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) d[i] = read();
    	for(int i = 1; i <= n; ++i) fa[i] = i, siz[i] = 1;
    	for(int i = 1; i <= n; ++i) {
    		int uf = find(a[i]), vf = find(b[i]);
    		if(uf != vf) fa[uf] = vf, siz[vf] += siz[uf];
    	}
    	for(int i = 1; i <= n; ++i) {
    		if(d[i] != 0) {
    			vis[find(d[i])] = true;
    		}
    	}
    	LL ans = 1;
    	for(int i = 1; i <= n; ++i) {
    		if(find(i) == i && !vis[i] && siz[i] > 1) {
    			ans = 2ll * ans % mod;
    		}
    	}
    	cout << ans << "\n";
    }
    
    signed main() {
    	int T = read();
    	while(T--) Main();
    	return 0;
    }
    

    D. Very Suspicious

    找规律题。

    考虑两条不平行的线相交,最多会产生 \(2\) 的贡献。

    因为这个六边形网络无限大,所以一定会有一个位置,是的当前放的这条线和之前放的所有与它不平行的线相交。

    然后记录一下三种线的数量,每次贪心选择放当前数量最少的哪一种线就是最优的放法。

    然后暴力跑一下 \(n= 10^9\) 的情况,发现只需要三万多条线。(忘记具体数了)

    然后你就可以暴力跑出 \(i\) 条线最多能搞出多少个三角形存下来。

    对于每次询问直接 lower_bound 即可。

    #include<bits/stdc++.h>
    #define LL long long 
    //#define int long long
    #define orz cout << "tyy YYDS!!!\n"
    using namespace std;
    const int MAXN = 2e5 + 10;
    const int INF = 1e9 + 7;
    const int mod = 998244353;
    
    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 ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    int biao[MAXN], Cnt = 0;
    
    void Calc(int n) {
    	int now = 0, ans = 0;
    	int a = 0, b = 0, c = 0;
    	while(now < n) {
    		if(a <= b && a <= c) {
    			now += 2 * (b + c);
    			ans ++;
    			a ++;
    		} else if(b <= a && b <= c) {
    			now += 2 * (a + c);
    			ans ++;
    			b ++;
    		} else if(c <= a && c <= b) {
    			now += 2 * (a + b);
    			ans ++;
    			c ++;
    		}
    		biao[ans] = now; 
    	}
    	Cnt = ans;
    //	cout << ans << "\n";
    }
    
    signed main() {
    	Calc(1500000000);
    //	cout << Cnt << "\n";
    	int T = read();
    	while(T--) {
    		int n = read();
    		int x = lower_bound(biao + 1, biao + Cnt + 1, n) - biao;
    		cout << x << "\n";
    	}
    	return 0;
    }
    

    E. Hemose on the Tree

    发现答案最优一定是 \(2^p\)

    考虑怎么构造,因为 \(x \oplus (x+2^p) = 2^p\),所以将他们两两配对。随便找一个点放上 \(2^p\) 作为根。

    然后可以根据这个点的父亲的第 \(p\) 位是否是 \(1\) 来判断两个数谁放到边上谁放到点上。

    #include<bits/stdc++.h>
    #define LL long long 
    //#define int long long
    #define orz cout << "tyy YYDS!!!\n"
    using namespace std;
    const int MAXN = 3e5 + 10;
    const int INF = 1e9 + 7;
    const int mod = 998244353;
    
    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 ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    struct edge { int to, id, nxt; }e[MAXN << 1];
    int head[MAXN], num_edge = 1;
    
    int p, n, now;
    int ans[MAXN], res[MAXN];
    
    void add_edge(int from, int to, int id) { e[++num_edge] = (edge){to, id, head[from]}, head[from] = num_edge; }
    
    void dfs(int u, int fa, int dep) {
    	for(int i = head[u]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if(v == fa) continue;
    		ans[v] = ++now;
    		res[e[i].id] = now + n;
    		if(!dep) swap(ans[v], res[e[i].id]);
    		dfs(v, u, dep ^ 1);
    	}
    }
    
    void Main() {
    	p = read(), n = (1 << p);
    	num_edge = 1, now = 0;
    	for(int i = 1; i <= n; ++i) head[i] = 0;
    	for(int i = 1, u, v; i < n; ++i) {
    		u = read(), v = read();
    		add_edge(u, v, i), add_edge(v, u, i);
    	}
    	dfs(n, 0, 1);
    	ans[n] = n;
    	printf("%d\n", n);
    	for(int i = 1; i <= n; ++i) printf("%d ", ans[i]); puts("");
    	for(int i = 1; i < n; ++i) printf("%d ", res[i]); puts("");
    }
    
    signed main() {
    	int T = read();
    	while(T--) Main();
    	return 0;
    }
    
  • 相关阅读:
    Java中的多线程你只要看这一篇就够了
    用Spring Boot颠覆Java应用开发
    Java Web 学习路线
    Java基本概念(2)J2EE里面的2是什么意思
    Java基本概念(1)什么是Java
    《Effective Java》读书笔记一(创建与销毁对象)
    Java:集合,对列表(List)中的数据(整型、字符串、日期等)进行排序(正序、倒序)的方法;字符串按照整型排序的方法
    Java:几个正则式应用(检查汉字、日期、EMAIL、手机号码的合法性,替换字符串等)
    Solr4:查询参数fq的用法(对结果进行过滤;两组关键词组合查询)
    Oracle删除重复记录只保留一条数据的几种方法
  • 原文地址:https://www.cnblogs.com/Silymtics/p/VPCF1670.html
Copyright © 2020-2023  润新知