zoukankan      html  css  js  c++  java
  • CodeForces

    pro:给定N个点,M条边,现在你要给一些连通块加边,使得至少存在一个连通块的大小是由4和7组成的数字。问至少加边数量。

    sol: 看似一个很难的题目。  首先不要想太难了,还是应该想能不能用背包做。 我们把块的大小相同的分到一组,就可以分组背包了。 然后注意到组别的大小其实不会太大,因为1*1+2*2+3*3+4*4+x*x<=1e5;   x是1e2级别的。 所以做100次多重背包。 总的复杂度也才O(100*N*K),K是个比较小的常数,真正的复杂度小于这个;

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=200010;
    int fa[maxn],num[maxn],sum[maxn];
    int dp[maxn],N;
    int find(int x)
    {
        if(fa[x]==x) return x;
        return fa[x]=find(fa[x]);
    }
    void pack(int v,int now)
    {
        for(int i=N;i>=v;i--){
            dp[i]=min(dp[i-v]+now,dp[i]);
        }
    }
    void solve(int v,int x)
    {
        int now=1;
        while(now<x){
            pack(v*now,now);
            x-=now;
            now*=2;
        }
        if(x) pack(v*x,x);
    }
    bool check(int x){
        int tx=x;
        while(x){
            int t=x%10;
            if(t!=4&&t!=7) return false;
            x/=10;
        }
        return true;
    }
    int main()
    {
        int M,v,u,fu,fv;
        scanf("%d%d",&N,&M);
        rep(i,1,N) num[i]=1,fa[i]=i;
        rep(i,1,M){
            scanf("%d%d",&u,&v);
            fu=find(u);
            fv=find(v);
            if(fu!=fv) num[fu]+=num[fv],fa[fv]=fu;
        }
        rep(i,1,N) {
            fu=find(i);
            if(fu==i) sum[num[fu]]++;
        }
        rep(i,1,N) dp[i]=N+M+1;
        rep(i,1,N)
          if(sum[i]) solve(i,sum[i]);
        int res=N+M+1;
        rep(i,1,N)
          if(check(i)) res=min(dp[i],res);
        if(res==N+M+1) puts("-1");
        else printf("%d
    ",res-1);
        return 0;
    }
  • 相关阅读:
    主线程MainThread与渲染线程RenderThread
    杀死进程的几种方式
    Android App的设计架构:MVC,MVP,MVVM与架构经验谈
    动画完全解析(二):补间动画原理及自定义动画
    SublimeText教程
    JqGrid自定义的列
    js 除法 取整
    js日期字符串增加天数的函数
    Oracle中的rownum和rowid
    jQuery判断对象是否是函数
  • 原文地址:https://www.cnblogs.com/hua-dong/p/10853917.html
Copyright © 2011-2022 走看看