CF95E Lucky Country

题目链接

题意:

幸运数是只由 47 构成的数, n n n 个顶点组成若干个连通块,求至少需要加入几条边可以构造出一个大小是幸运数的连通块

题解:

先求出各个连通块大小,然后用 d p ( i ) dp(i) dp(i) 表示构成大小为 i i i 的连通块需要至少 d p ( i ) dp(i) dp(i) 条边,用二进制优化多重背包复杂度为 O ( n ∗ s q r t ( n ) ∗ l o g ( k ) ) O(n*sqrt(n)*log(k)) O(nsqrt(n)log(k))

struct DSU{
	int n;
	vector<int>f,siz;
	DSU(int n):n(n),f(n+1),siz(n+1,1){iota(f.begin(),f.end(),0);}
	int leader(int x){ return x==f[x]?x:f[x]=leader(f[x]); }
	bool same(int x,int y){ return leader(x)==leader(y); }
	int size(int x){ return siz[x]; }
	bool merge(int x,int y){
		x=leader(x),y=leader(y);
		if(x==y) return false;
		f[x]=y,siz[y]+=siz[x];
		return true;
	}
};
void problem_solver() {
	int n,m; cin>>n>>m;
	DSU d(n);
	for(int i=0;i<m;i++){
		int u,v; cin>>u>>v;
		d.merge(u,v);
	}
	vector<int>dp(n+1,INF);
	dp[0]=0;
	vector<int>cnt(n+1),vis(n+1);
	for(int i=1;i<=n;i++) 
		if(!vis[d.leader(i)]) cnt[d.size(d.leader(i))]++,vis[d.leader(i)]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;cnt[i];j*=2){
			int p=min(j,cnt[i]);
			cnt[i]-=p;
			int w=p*i;
			for(int k=n;k>=w;k--)
				dp[k]=min(dp[k],dp[k-w]+p);
		}
	}
	auto check=[&](int x){
		while(x){
			if(x%10!=4&&x%10!=7) return 0;
 			x/=10;
		}
		return 1;	
	};
	int ans=INF;
	for(int i=1;i<=n;i++) if(check(i)) ans=min(ans,dp[i]);
	cout<<(ans==INF?-1:ans-1)<<'\n';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值