• 【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");
    }
    
  • 相关阅读:
    SNAT的作用是什么
    Maven命名规范收集
    Linux下Git命令中文显示乱码的问题解决:274232350256256346200273347273223
    HttpClient中文乱码问题排查
    Ubuntu 16.04通过NetworkManager(GUI)配置网桥
    HTML5 Video P2P技术研究(转)
    CentOS 6.9下KVM虚拟机快照创建、删除、恢复(转)
    CentOS 6.9下KVM虚拟机通过virt-clone克隆虚拟机(转)
    开源规则引擎 drools
    评估系统负载
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090915.html
Copyright © 2020-2023  润新知