zoukankan      html  css  js  c++  java
  • 95E Lucky Country

    传送门

    题目大意

    如果一个数中不包含除4和7之外的数字则是幸运数。有n个岛屿,通过双向道路连接。这些岛屿被分为几个地区。每个岛属于恰好一个区域,同一区域中的任何两个岛之间存在道路,不同区域的任何两个岛之间没有路径。如果一个地区的岛屿数量是一个幸运数字,则这个地区是幸运的。问最少增加几条道路能创建一个幸运地区。

    分析

    首先直接缩点,这样我们就得到了许多数字,所以任务就变成了用最少数量的不同数字组成幸运数字,首先我们不难想到O(n2)做法:枚举1~n的每一个数字,然后枚举所有现有数字,暴力转移。但显然这样是不行的,所以我们考虑优化转移。我们发现有一些数字重复出现了多次,所以我们可以考虑把它们放在一起记录,即记录大小为x的数字共有s个。然后我们再转移时利用倍增的思想直接将某个数字的个数二进制转换,这样它就可以变成了一个背包问题,可以证明此时的复杂度变为了O(nlogn)。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    #define sp cout<<"---------------------------------------------------"<<endl
    const int inf=0x3f3f3f3f;
    int dfn[100010],low[100010],ist[100010],s[100010],sum,cnt,tot[100010];
    stack<int>a;
    vector<int>v[100010];
    int dp[100010];
    inline void tarjan(int x){
          dfn[x]=low[x]=++cnt;
          a.push(x);
          ist[x]=1;
          for(int i=;i<v[x].size();i++)
            if(!dfn[v[x][i]]){
              tarjan(v[x][i]);
              low[x]=min(low[x],low[v[x][i]]);
            }else if(ist[v[x][i]]){
              low[x]=min(low[x],dfn[v[x][i]]);
            }
          if(dfn[x]==low[x]){
              sum++;
              while(1){
                  int u=a.top();
                  a.pop();
                  ist[u]=0;
                  s[sum]++;
                  if(u==x)break;
              }
          }
    }
    int main(){
          int n,m,i,j,k;
          scanf("%d%d",&n,&m);
          memset(dp,0x3f,sizeof(dp));
          for(i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
          }
          for(i=1;i<=n;i++)
            if(!dfn[i])
              tarjan(i);
          for(i=1;i<=sum;i++)
            tot[s[i]]++;
          dp[0]=0;
          for(i=1;i<=n;i++)
            if(tot[i]){
              int k=tot[i];
              while(k){
                  int x=(k+1)/2;
                for(j=n;j>=i*x;j--)
                  dp[j]=min(dp[j],dp[j-i*x]+x);
                k/=2;
              }
            }
          int ans=inf;
          for(i=4;i<=n;i++){
              int x=i,ok=1;
              while(x){
                if(x%10!=4&&x%10!=7){ok=0;break;}
                x/=10;
            }
            if(!ok)continue;
            ans=min(ans,dp[i]);
          }
          if(ans==inf)puts("-1");
            else printf("%d
    ",ans-1);
          return 0;
    }
  • 相关阅读:
    科学开源项目 : 建立一个 新的 光衍射 模型
    光不是电磁波 摩擦力不是电磁力
    收录一篇 贝尔不等式 的 文章
    数学家 程序员 哲学家 艺术家
    论 数学 的 工具性
    数学 怎么用?
    随便说说 广义相对论 的 时间膨胀
    逻辑物理学 : 光子 有 质量 吗 ?
    我对 “光子有质量 , 引力对光子有作用” 存疑
    收录一些 高等数学 的 文章
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/9333773.html
Copyright © 2011-2022 走看看