Codeforces Round #628 (Div. 2)

传送门:

https://codeforces.com/contest/1325

A

很简单的构造,输出 \(1,n-1\) 即可。

int main(){
	int T; cin>>T;
	while(T--){
		 int n; cin>>n;
		 cout<<1<<' '<<n-1<<endl;
	}
	return 0;
}

B

需要做一定的转化,发现就是在求数列中有多少不同的值。

int main(){
	int T; cin>>T;
	while(T--){
		int n; cin>>n;
		unordered_set<int> st;
		rep(i,1,n){
			int v; read(v);
			st.insert(v);
		}
		cout<<(int)st.size()<<endl;
	}
	return 0;
}

C

  • 当树退化成链的时候,怎么构造都是一个结果,直接按顺序赋值即可。
  • 如果树不是链,说明存在一个点的度数大于 \(3\),那我们在这个点上将 \(0,1,2\) 三个值分配下来即可,这样就能够保证答案为 \(2\) 了。
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=1e5+50, M=N<<1;
 
struct Edge{
	int u, v, w;
}e[N];
 
int deg[N];
bool vis[N];
 
int main(){
	int n; cin>>n;
	rep(i,1,n-1){
		int u, v; read(u), read(v);
		e[i]={u, v};
		deg[u]++, deg[v]++;
	}
	
	int cnt=0;
	rep(i,1,n) cnt=max(cnt, deg[i]);
	
	if(cnt<=2){
		rep(i,1,n-1) cout<<i-1<<endl;
		return 0;
	}
	
	int t;
	rep(i,1,n) if(deg[i]>2){
		t=i;
		break;
	}
	
	int cur=0;
	rep(i,1,n-1){
		int u=e[i].u, v=e[i].v;
		if(u==t || v==t && cur<=2) e[i].w=cur++, vis[i]=true;
	}
	
	rep(i,1,n-1) if(!vis[i]) e[i].w=cur++;
	rep(i,1,n-1) cout<<e[i].w<<endl;
	
	return 0;
}

D

要求构造一个最短的数列使得异或值为 \(u\),和为 \(v\)

  • 首先特判 \(0~0\) 的情况
  • 如果 \(u>v\),肯定无解,输出 -1
  • \(u=v\),一个 \(u\) 就是答案了。
  • 剩下就是 \(u<v\) 的情况,\(u,v\) 奇偶性必须相同,否则无解,因为对于数列异或,其二进制意义下的第一位一定相等,也就是 \(u,v\) 奇偶性相同。然后在 \(u,v\) 奇偶性相同的前提下,我们首先发现答案长度一定小于等于 \(3\),构造方案就是 \(\{u,\frac{v-u}{2},\frac{v-u}{2}\}\),如果 \(u \&\frac{v-u}{2}=0\)​,说明二者可以合并,那么此时答案为 \(2\)
int main(){
	ll u, v; cin>>u>>v;
	if(!u && !v) puts("0");
	else if(u>v) puts("-1");
	else if(u==v) cout<<1<<endl<<u<<endl;
	else if(u<v){
		ll t=v-u>>1;
		if((u&1)!=(v&1)) puts("-1");
		else if(!(u&t)){
			puts("2");
			cout<<(u|t)<<' '<<t<<endl;
		}
		else{
			puts("3");
			cout<<u<<' '<<t<<' '<<t<<endl;
		}
	}
	return 0;
}

E

因为每个数 \(a_i\) 质因子至多两个,故 \(a_i\) 可以作为边建图,然后边的两点是质因子(或 \(1\))。

下面的任务是找到最小环。

因为大于 \(1000\) 的点间不存在边,所以以值 \(< 1000\) 的点为起点多次进行 bfs 找最小环即可。

对于每次 bfs,队列里的元素是当前点 \(u\)​ 和它的前驱 \(fa\)​,

\(u\) 展开它所连接的点 \(go\) 时,

如果 \(go\)​ 是 \(fa\)​ 则跳过,否则看看 \(go\)​ 是不是 \(vis\)​ 过的点,不是则入队,是则更新环。

const int N=1e5+5, V=1e6+5, M=N<<1;
 
int n;
 
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++;
}
 
int prime[V], cnt;
bool st[V];
int id[V];
void init(){
	id[1]=1;
	rep(i,2,V-1){
		if(!st[i]) prime[++cnt]=i, id[i]=cnt+1;
		for(int j=1; i*prime[j]<V; j++){
			st[i*prime[j]]=1;
			if(i%prime[j]==0) break;
		}
	}
}
 
bool vis[V];
vi S;
 
void upd(int n){
	int u=0, v=0;
	for(int i=2; i*i<=n; i++){
		if(n%i==0){
			int p=0;
			while(n%i==0) n/=i, p++;
			if(p&1){
				if(!u) u=i;
				else v=i;
			}
		}
	}
	if(n>1){
		if(!u) u=n;
		else v=n;
	}
	
	if(!u && !v){
		puts("1");
		exit(0);
	}
	else if(!v){
		if(!vis[u] && u<=1000) vis[u]=true, S.pb(id[u]);
		if(!vis[1]) vis[1]=true, S.pb(id[1]);
		u=id[u], v=id[1];
		add(u, v), add(v, u);
	}
	else{
		if(!vis[u] && u<=1000) vis[u]=true, S.pb(id[u]);
		if(!vis[v] && v<=1000) vis[v]=true, S.pb(id[v]);
		u=id[u], v=id[v];
		add(u, v), add(v, u);
	}
}
 
struct Node{
	int u, fa;
}q[V];
int tt, hh;
 
int ans=INF;
 
int d[N];
 
int main(){
	init();
	cin>>n;
	
	memset(h, -1, sizeof h);
	rep(i,1,n){
		int v; read(v);
		upd(v);
	}
	
	for(auto s: S){
		rep(i,1,cnt) d[i]=INF, vis[i]=false; 
		tt=-1, hh=0;
		q[++tt]={s, -1};
		vis[s]=true;
		d[s]=0;
		
		while(tt>=hh){
			auto t=q[hh++];
			int u=t.u, fa=t.fa;
			for(int i=h[u]; ~i; i=e[i].next){
				int go=e[i].to;
				if(go==fa) continue;
				if(!vis[go]){
					q[++tt]={go, u};
					vis[go]=true;
					d[go]=d[u]+1;
				}
				else ans=min(ans, d[u]+d[go]+1);
			}
		}
	}
	
	cout<<(ans==INF? -1: ans)<<endl;
	
	return 0;
}

F

dfs 树。

我们记 \(lim = \lceil \sqrt n \rceil\)

注意到对于一个无向图的边集所对应的 dfs 树的边集只可能是树边回边

记当前点为 \(u\)\(u\) 出发沿着回边走到的点为 \(go\)

我们有当 \(dep[u]-dep[go]+1\geq lim\) 时,图上存在大小大于 \(lim\) 的环。

假如图不存在大小大于 \(lim\)​ 的环,那么这意味着对于每个点,其最多有 \(lim-2\)​​ 条回边(考虑极端情况即得),也就是说你在 dfs 树上选一个点,最多有 \(lim-2\) 个祖先不能被选取,我们在回溯的过程中做选点操作就可以了。

复杂度为 \(O(N+M)\)

// Problem: F. Ehab's Last Theorem
// Contest: Codeforces - Codeforces Round #628 (Div. 2)
// URL: https://codeforces.com/contest/1325/problem/F
// Memory Limit: 256 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define debug(x) cerr << #x << ": " << x << endl
#define pb push_back
#define eb emplace_back
#define set0(a) memset(a,0,sizeof(a))
#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 ceil(a,b) (a+(b-1))/(b)

#define all(x) (x).begin(), (x).end()
#define SUM(a) accumulate(all(a), 0LL)
#define MIN(a) (*min_element(all(a)))
#define MAX(a) (*max_element(all(a)))
#define lb(a, x) distance(begin(a), lower_bound(all(a), (x)))
#define ub(a, x) distance(begin(a), upper_bound(all(a), (x)))

#define INF 0x3f3f3f3f
#define ll_INF 0x7f7f7f7f7f7f7f7f

using pii = pair<int, int>;
using pdd = pair<double, double>;
using vi = vector<int>;
using vvi = vector<vi>;
using vb = vector<bool>;
using vpii = vector<pii>;
using ll = long long;
using ull = unsigned 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=2e5+5, M=N<<2;

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++;
}

int n, m;
int lim;

bool vis[N]; // 标记是否作为独立集中的点
vi res; //  记录独立集
int d[N]; // 记录深度,同时标记 dfs 中是否访问过该点。
int stk[N], top; // 维护当前 dfs 栈中的点集。

void dfs(int u){
	stk[++top]=u;
	d[u]=top;
	for(int i=h[u]; ~i; i=e[i].next){
		int go=e[i].to;
		if(!d[go]) dfs(go);
		else if(d[u]-d[go]+1>=lim){
			puts("2"); cout<<d[u]-d[go]+1<<endl;
			rep(i,d[go],d[u]) cout<<stk[i]<<' ';
			exit(0);
		}
	}
	
	if(!vis[u]){
		res.pb(u);
		for(int i=h[u]; ~i; i=e[i].next){
			int go=e[i].to;
			vis[go]=true;
		}
	}
	
	top--;
}

int main(){
	memset(h, -1, sizeof h);	
	cin>>n>>m;
	rep(i,1,m){
		int u, v; read(u), read(v);
		add(u, v), add(v, u);
	}
	
	lim=sqrt(n-1)+1;
	dfs(1);
	
	puts("1");
	rep(i,0,lim-1) cout<<res[i]<<' ';
	
	return 0;
}
posted @ 2021-10-20 22:19  HinanawiTenshi  阅读(46)  评论(0编辑  收藏  举报