zoukankan      html  css  js  c++  java
  • 正睿 2021 Noip 十连测 Day2

    A

    写个暴力找规律即可。

    B

    (80) 分做法:数位 dp,设 (f_{i,j}) 为低 (i) 位,(mod a=j) 是否可行,并记录一下转移。

    考虑建一张 (a) 个点 (0sim(a-1)) 的图,对于每个合法的转移 (x o (10x+y)mod a) 连边,最小位数就是任意非零点到 (0) 号点的最短路,可以直接 bfs 出来。

    然后贪心地从高位到低位确定即可。

    C

    注意到任意选边都能构成完美匹配的条件,是原图的每个极大连通块都是左右部点数相同的完全二分图。

    于是问题变成了:给你若干个连通块,你需要合并其中一些,使得每个连通块内左右部点数相同,且所有连通块左部点数的平方和最小。

    因为 (nle 25),考虑大力状压:把左右部点数相同的先去掉,然后记录左右部的孤点各有多少个,以及剩下的连通块。

    (f_{S,i,j}) 为把 (S) 内的所有连通块拼成若干个左右部点数相同的连通块,并且使用了 (i) 个左部孤点,(j) 个右部孤点,平方和最小是多少。转移时枚举 (S) 的一个子集,强制配上一些孤点使得这个子集并成一个左右部点数相同的连通块,贡献到 (f) 上即可。

    复杂度:考虑最多形成多少个连通块?可以发现左部一个点、右部两个点(或者反过来)能形成 (2/3n) 个连通块。于是复杂度是 (mathcal{O}(3^{2/3n}n^2))。算一下可以发现这玩意最多 (4 imes 10^{10}),但连通块个数越多,孤点个数越小,所以远远跑不满。

    代码
    #include <cstdio>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
    #define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
    template<typename T> void Read(T &x){
    	x=0;int _f=1;
    	char ch=getchar();
    	while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar();
    	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    	x=x*_f;
    }
    template<typename T,typename... Args> void Read(T &x,Args& ...others){
    	Read(x);Read(others...);
    }
    typedef long long ll;
    const int N=27,M=17;
    int T,n;char a[N][N];
    struct DSU{
    	int fa[N<<1];
    	int Find(int p){
    		return fa[p]==p?p:fa[p]=Find(fa[p]);
    	}
    	void Union(int p,int q){
    		fa[Find(p)]=Find(q);
    	}
    };
    int dots[2][1<<M],dot[2],siz[2][N<<1],cnt,bl[2][N<<1],cost[1<<M],f[1<<M][N][N];
    DSU dsu;
    int main(){
    	Read(T);
    	while(T--){
    		memset(dots,0,sizeof dots);
    		memset(siz,0,sizeof siz);
    		cnt=dot[0]=dot[1]=0;
    		memset(bl,0,sizeof bl);
    		memset(cost,0,sizeof cost);
    		Read(n);
    		For(i,1,n*2) dsu.fa[i]=i;
    		int ans=0;
    		For(i,1,n){
    			scanf("%s",a[i]+1);
    			For(j,1,n) if(a[i][j]=='1') dsu.Union(i,j+n),--ans;
    		}
    		For(i,1,n*2){
    			++siz[i>n][dsu.Find(i)];
    		}
    		For(i,1,n*2){
    			if(dsu.Find(i)!=i) continue;
    			if(siz[0][i]==siz[1][i]) ans+=siz[0][i]*siz[1][i];
    			else if(siz[0][i]+siz[1][i]==1) ++dot[siz[1][i]];
    			else{
    				++cnt;
    				bl[0][cnt]=siz[0][i],bl[1][cnt]=siz[1][i];
    			}
    		}
    		int S=(1<<cnt)-1;
    		For(st,1,S){
    			for(int i=1;i<=cnt;++i){
    				if((st&1<<(i-1))==0) continue;
    				dots[0][st]+=bl[0][i],dots[1][st]+=bl[1][i];
    			}
    			if(dots[0][st]>dots[1][st]){
    				cost[st]=dots[0][st]*dots[0][st];
    				dots[1][st]=dots[0][st]-dots[1][st],dots[0][st]=0;
    			}else{
    				cost[st]=dots[1][st]*dots[1][st];
    				dots[0][st]=dots[1][st]-dots[0][st],dots[1][st]=0;
    			}
    		}
    		For(i,0,S) For(j,0,dot[0]) For(k,0,dot[1]) f[i][j][k]=0x3f3f3f3f;
    		f[0][0][0]=0;
    		For(i,1,S){
    			for(int st=i;st;st=(st-1)&i){
    				For(j,dots[0][st],dot[0]){
    					For(k,dots[1][st],dot[1]){
    						f[i][j][k]=min(f[i][j][k],f[i^st][j-dots[0][st]][k-dots[1][st]]+cost[st]);
    					}
    				}
    			}
    		}
    		int res=0x3f3f3f3f;
    		For(i,0,min(dot[0],dot[1])){
    			res=min(res,f[S][dot[0]-i][dot[1]-i]+i);
    		}
    		printf("%d
    ",res+ans);
    	}
    	return 0;
    }
    
    Written by Alan_Zhao
  • 相关阅读:
    angular 1.26 版本 window.history.back() 自动去顶部
    CK editor 制作 ”小“plugin
    CSS 3 过渡效果之jquery 的fadeIn ,fadeOut
    了解 : angular controller link nginit 顺序
    规范 : jobbox 中英文
    了解 : angular translate 和 google translate 和 微软 translate
    业务逻辑 : 未完 : easybook.com
    List和ArrayList的区别
    Select什么时候会产生重作日志
    几点对专用服务器与共享服务器差异的理解
  • 原文地址:https://www.cnblogs.com/alan-zhao-2007/p/zroi-2021-noip-10lian-day2.html
Copyright © 2011-2022 走看看