【Codeforces#599】简要题解

这套题目做得我好难受,DE比较神仙,所以还没有做出来
Codeforces#599

A

当两个格子的距离是N的因子(非1)时两个格子颜色相同,求最后有多少个不同颜色的格子(n<=1012)

  • 格子的个数就是N的因子的GCD。
  • 首先肯定只有N的质因子有用。
  • 然后如果N有多个质因子,因为ax+by=gcd(a,b)=1一定有解,所以最小跨越的距离就是1
  • 否则如果只有一个质因子,显然就是这个质因子。
  • 如果这是一个质数的话,那就是它自己。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ll long long 
using namespace std;

ll n;

int main(){
	freopen("ceshi.in","r",stdin);
	scanf("%lld",&n);
	for(int i=2;i<=sqrt(n);i++) if (n%i==0){
		while (n%i==0) n/=i;
		if (n!=1) printf("1
");
		else printf("%d",i);
		return 0;
	}
	printf("%lld",n);
}

B

求一个完全图的MST,其中有m条边边权为1,其他边权为0.

  • 奇奇怪怪的想法都蹦了出来(除了正解)。
  • 首先随便加入一个点。
  • 考虑我们想要找到边权为0的边。
  • 因为当前生成树中的点以1的边权连向一些点,所以不妨给这些点记录一下被覆盖的次数。
  • 如果有一个点的被覆盖次数小于当前的生成树中的点数,那么一定有一条0的边。
  • 用一个堆维护一下被覆盖的次数。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 100005
using namespace std;

int n,m,i,j,k,x,y,vis[maxn],ans,nm[maxn];
int em,e[maxn*2],nx[maxn*2],ls[maxn],tot;
struct node{
	int x,i;
	node(int _x=0,int _i=0){x=_x,i=_i;}
} d[maxn];
int operator<(node a,node b){return a.x<b.x||a.x==b.x&&a.i<b.i;}


void insert(int x,int y){
	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
}

void down(int x){
	for(int y=x*2;y<=tot&&d[y]<d[x]||y+1<=tot&&d[y+1]<d[x];x=y,y=x*2){
		if (y+1<=tot&&d[y+1]<d[y]) y++;
		swap(d[x],d[y]);
		nm[d[x].i]=x,nm[d[y].i]=y;
	}
}

void up(int x){
	for(int y=x/2;y&&d[x]<d[y];x=y,y=x/2){
		swap(d[x],d[y]);
		nm[d[x].i]=x,nm[d[y].i]=y;
	}
	down(x);
}

void change(int x){
	d[x].x++;
	down(x);
}

void del(int x){
	swap(d[x],d[tot]),tot--;
	if (x<=tot) nm[d[x].i]=x,up(x);
}

void add(node p){
	++tot,nm[p.i]=tot,d[tot]=p;
	up(tot);
}

int main(){
	freopen("ceshi.in","r",stdin);
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++) {
		scanf("%d%d",&x,&y);
		insert(x,y);
	}
	for(i=1;i<=n;i++) add(node(0,i));
	for(i=0;i<n;i++) {
		node tmp=d[1];
		if (tmp.x==i) ans++;
		x=tmp.i,vis[x]=1;
		for(j=ls[x];j;j=nx[j]) if (!vis[e[j]]) 	
			change(nm[e[j]]);
		del(1);
	}
	printf("%d",ans-1);
}

C

给K(K<=15)个序列,每一个有ni(ni<=5000)个a,求一种方案将每一个序列的一个元素移动到一个序列中,每个序列移进来一个,移出去一个,使得最后每一个序列的a的和相等。

  • 为什么我觉得C比A和B都更简单呢??(除了代码长了点以外)
  • 暴力枚举起点哪一个移出去,因为所有a都是不同的,并且目标都是确定的,所以只用O(Klogn)扫一遍看看是不是一个环(用个map)。
  • 因为可能是很多个互相独立的环,所以直接子集转移就好了。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<map>
#define mem(a) memset(a,0,sizeof(a))
#define maxk 16
#define maxn 5005
#define ll long long 
using namespace std;

int K,n[maxk],i,j,k,S,a[maxk][maxn],vis[maxk];
int f[1<<maxk],g[1<<maxk],g0[1<<maxk];
int p[1<<maxk][maxk],q[1<<maxk][maxk],pp[maxk],qq[maxk];
ll sum0,sum[maxk],need,res;
struct node{
	int x,y;
	node(int _x=0,int _y=0){x=_x,y=_y;}
};
map<int,node> s;

void read(int &x){
	x=0; char ch=getchar(); int tp=1;
	for(;ch!='-'&&(ch<'0'||ch>'9');ch=getchar());
	if (ch=='-') tp=-1,ch=getchar();
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	x=x*tp;
}

int dg(int T,int i,int S){
	if (i>K){
		if (f[T]&&g[S^T]) {
			g0[S]=T,g[S]=1;
			return 1;
		}
		return 0;
	}
	if (dg(T,i+1,S)) return 1;
	if ((S&(1<<i-1))&&dg(T|(1<<i-1),i+1,S)) return 1;
	return 0;
}

int main(){
	freopen("ceshi.in","r",stdin);
	read(K);
	for(i=1;i<=K;i++){
		read(n[i]);
		for(j=1;j<=n[i];j++) {
			read(a[i][j]);
			sum[i]+=a[i][j],sum0+=a[i][j];
			s[a[i][j]]=node(i,j);
		}
	}
	if (sum0%K) {printf("No");return 0;} 
	need=sum0/K;
	for(int sti=1;sti<=K;sti++) {
		for(int st=1;st<=n[sti];st++) {
			mem(vis),mem(pp),mem(qq);
			res=need-(sum[sti]-a[sti][st]);
			vis[sti]=1,i=sti,pp[sti]=st,S=1<<sti-1;
			node now=s[res];
			while (now.x&&!vis[now.x]){
				vis[now.x]=1,pp[now.x]=now.y,qq[now.x]=i,S|=1<<now.x-1;
				res=need-(sum[now.x]-a[now.x][now.y]);
				i=now.x,now=s[res];
			}
			if (now.x==sti&&res==a[sti][st]&&!f[S]) {
				qq[sti]=i,f[S]=1;
				memcpy(p[S],pp,sizeof(pp));
				memcpy(q[S],qq,sizeof(qq));
			}
		}
	}
	memcpy(g,f,sizeof(f));
	for(S=1;S<1<<K;S++) if (!g[S])
		dg(0,1,S); else g0[S]=S;
	if (g[(1<<K)-1]) {
		printf("Yes
");
		mem(pp),mem(qq);
		S=(1<<K)-1;
		while (S) {
			int T=g0[S];
			for(i=1;i<=K;i++) if (T&(1<<i-1)) 
				pp[i]=p[T][i],qq[i]=q[T][i];
			S^=T;
		}
		for(i=1;i<=K;i++) printf("%d %d
",a[i][pp[i]],qq[i]);
	} else printf("No");
}
原文地址:https://www.cnblogs.com/DeepThinking/p/13090915.html