Codeforces Round #485 (Div. 2)

传送门:
https://codeforces.com/contest/987

A

模拟,开个 map

int main(){
	map<char, string> w;
	w['p']="Power", w['g']="Time", w['b']="Space", w['o']="Soul", w['r']="Reality", w['y']="Mind";
	int n; cin>>n;
	while(n--){
		string s; cin>>s;
		char ch=s[0];
		w.erase(ch);
	}
	
	cout<<w.size()<<endl;
	for(auto [x, y]: w) cout<<y<<endl;
	
	return 0;
}

B

简单的高中数学。

取个 \(ln\)​,发现原式等价于 \(y/lny > x/lnx\)​(此时 \(x,y \ne 1\),相应地需要对此特判)。

\(f(t) = t/lnt\)​​,对 \(f(t)\)​ 求导可以发现:在 \(t>e\)​ 的时候函数是单调增的,那么在 \(t\geq 3\)​ 的时候我们直接对 \(x,y\)​​ 的大小进行判断即可。

\(x,y \leq 3\) 的时候直接计算。

int main(){
	int x, y; cin>>x>>y;
	if(x==1){
		if(y==1) putchar('=');
		else putchar('<');
		return 0;
	}
	if(y==1){
		if(x==1) putchar('=');
		else putchar('>');
		return 0;
	}
	
	if(x<5 && y<5){
		int a=pw(x, y), b=pw(y, x);
		if(a>b) putchar('>');
		else if(a==b) putchar('=');
		else putchar('<');
		return 0;
	}
	
	int a=x, b=y;
	if(a>b) putchar('<');
	else if(a==b) putchar('=');
	else putchar('>');
	return 0;
}

C

\(N\) 的范围支持 \(O(N^2)\),因此考虑枚举两维 \(i, j\),然后求位置 \(k\)​ 的贡献,这个贡献可以通过预处理信息:位置 \(j\) 之后满足 \(s[k] > s[j]\) 的位置的 \(c[k]\)​ 的最小值 来求出。

// Problem: C. Three displays
// Contest: Codeforces - Codeforces Round #485 (Div. 2)
// URL: https://codeforces.com/contest/987/problem/C
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()

#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;

inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=3030;

int s[N], c[N], n;
int g[N];

int main(){
	cin>>n;
	rep(i,1,n) read(s[i]);
	rep(i,1,n) read(c[i]);
	
	rep(i,1,n){
		g[i]=1e9;
		rep(j,i+1,n) if(s[j]>s[i]) g[i]=min(g[i], c[j]);
	}
	
	int res=1e9;
	rep(i,1,n){
		rep(j,i+1,n) if(s[j]>s[i]){
			int t=c[i]+c[j]+g[j];
			res=min(res, t);
		}
	}
	cout<<(res==1e9? -1: res)<<endl;
	
	return 0;
}

D

注意到商品的种类数并不多,我们可以从此入手。

考虑每种商品离每个点 \(u\) 的最短路。

这就是一个多源 bfs 问题。

考虑对于每种商品 \(k\),将 \(k\) 所在的所有点作为源点求一次 bfs 即可。

const int N=1e5+5, M=N<<1;
 
int n, m, k, s;
 
struct Edge{
	int to, next;
}e[M];
 
int h[N], tot;
 
void add(int u, int v){
	e[tot].to=v, e[tot].next=h[u], h[u]=tot++;
}
 
vector<int> node[N];
int d[N][110];
bool vis[N];
void build(vector<int> &P, int ty){
	queue<int> q;
	rep(i,1,n) vis[i]=false;
	for(auto i: P) q.push(i), vis[i]=true;
	vector<int> dis(n+1);
	
	while(q.size()){
		int u=q.front(); q.pop();
		for(int i=h[u]; ~i; i=e[i].next){
			int go=e[i].to;
			if(!vis[go]){
				vis[go]=true;
				dis[go]=dis[u]+1;
				q.push(go);
			}
		}
	}	
	
	rep(i,1,n) d[i][ty]=dis[i];
}
 
int main(){
	memset(h, -1, sizeof h);
	cin>>n>>m>>k>>s;
	rep(i,1,n){
		int x; read(x);
		node[x].pb(i);
	}
	
	rep(i,1,m){
		int u, v; read(u), read(v);
		add(u, v), add(v, u);
	}
	
	rep(i,1,k) build(node[i], i);
	
	rep(i,1,n){
		sort(d[i]+1, d[i]+1+k);
		int res=0;
		rep(j,1,s) res+=d[i][j];
		cout<<res<<' ';
	}
	cout<<endl;
	
	return 0;
}

E

注意到每一次交换,逆序对的奇偶性都会发生变化,而且,注意到 \(7n+1 - 3n = 4n + 1\) 一定为奇数,也就是二人的所得到的排列逆序对数一定不同,所以通过此来判断即可。

#define int long long 
 
const int N=1e6+50;
 
inline int read(){
   int s=0,w=1;
   char ch=getchar();	
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
 
int res, n, w[N], tmp[N];
 
void cdq(int l, int r){
	if(l>=r) return;
	int mid=l+r>>1;
	cdq(l, mid), cdq(mid+1, r);
	
	int sum=0;
	for(int k=l, i=l, j=mid+1; k<=r; k++)
		if(j>r || i<=mid && w[i]>w[j]) sum++, tmp[k]=w[i++];
		else tmp[k]=w[j++], res+=sum;
	for(int k=l; k<=r; k++) w[k]=tmp[k];
}
 
signed main(){
	n=read();
	for(int i=1; i<=n; i++) w[i]=read();
	
	cdq(1, n);
	cout<<((res-3*n)&1? "Um_nik": "Petr")<<endl;
	
	return 0;
}

F

分析

思想比较有意思的图论题。

为了符合习惯,这里约定 \(n\)​​​ 代表题目所给的点的编号\(U=2^m - 1\)​​ 是值域(同时也代表全集)。

考虑建图。

首先对图进行加点,将点数补至 \(2^m\)

记一个点的编号为 \(u\)​​​,那么它能够到达的极大的点编号\(go = u\oplus U\)​​​,并且 \(u\)​​ 能够到达的所有点编号一定是 \(go\)​​ 的子集,考虑将 \(u\)\(go\) 连边。

因此对于题目所给的每个点 \(u\)​​,我们需要设计一个算法,将它能够到达的所有点进行标记(访问),并相应地更新答案。

具体地,可以从 \(go = u\oplus U\)​​ 出发做一遍 dfs:沿着 \(go\) 能到达的点继续搜。但同时,\(go\) 的子集也需要标记,直接枚举是 \(O(2^m)\) 肯定行不通,故考虑对 \(go\) 对应的二进制数位进行枚举,这样就能将枚举的复杂度控制在 \(O(m)\)

// Problem: F. AND Graph
// Contest: Codeforces - Codeforces Round #485 (Div. 2)
// URL: https://codeforces.com/contest/987/problem/F
// Memory Limit: 256 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()

#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;

inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=1<<22|1, M=N;

int id[N];
int n, m;

struct Edge{
	int to, next;
}e[M];

int h[N], tot;

void add(int u, int v){
	e[tot].to=v, e[tot].next=h[u], h[u]=tot++;
}

bool vis[N];

void dfs(int u){
	vis[u]=true;
	rep(i,0,m-1) if(u>>i&1){
		int go=u^(1<<i);
		if(!vis[go]) dfs(go);
	}
	
	for(int i=h[u]; ~i; i=e[i].next){
		int go=e[i].to;
		if(!vis[go]) dfs(go);
	}
}

int main(){
	memset(h, -1, sizeof h);
	cin>>m>>n;
	int U=(1<<m)-1;
	rep(i,1,n) read(id[i]);
	
	rep(i,1,n) add(id[i], id[i]^U);
	
	int res=0;
	rep(i,1,n) if(!vis[id[i]]){
		res++;
		vis[id[i]]=true;
		dfs(id[i]^U);
	}
	cout<<res<<endl;
		
	return 0;
}
posted @ 2022-03-11 21:54  HinanawiTenshi  阅读(31)  评论(0编辑  收藏  举报