zoukankan      html  css  js  c++  java
  • bzoj 1119 [POI2009] SLO & bzoj 1697 牛排序 —— 置换+贪心

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1119

    https://www.lydsy.com/JudgeOnline/problem.php?id=1697

    原序列到目标序列的置换,可以找出一些循环节;

    发现如果按顺序把一个循环节换下来,如果长度为 l,则第一个数被算了 l-1 次,其它数都是 1 次;

    为了代价最小,还可以利用循环节外面的数,做法就是先把它换进来,然后让它算 l-1 次,再换出去;

    贪心地取个 min 即可;原来还想过一开始把数字作为位置,位置作为数字,则代价就算在位置上了,但是这样找出了循环节,似乎不一定是能按顺序换的...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const xn=1e4+5,inf=1e5+5;
    int n,w[xn],t[xn],b[xn],mn,mnn,sta[xn],tot,ans,sum;
    bool vis[xn];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    void dfs(int x)
    {
      sta[++tot]=x; vis[x]=1; 
      mn=min(mn,w[x]); sum+=w[x];
      if(!vis[b[x]])dfs(b[x]);
    }
    int main()
    {
      n=rd(); mnn=inf;
      for(int i=1;i<=n;i++)w[i]=t[i]=rd(),mnn=min(mnn,w[i]);
      sort(t+1,t+n+1);
      for(int i=1,x;i<=n;i++)
        {
          x=lower_bound(t+1,t+n+1,w[i])-t;
          b[x]=i;
        }
      for(int i=1;i<=n;i++)
        {
          if(vis[i])continue;
          tot=0; mn=inf; sum=0;
          dfs(i); if(tot==1)continue;
          ans+=min(sum+mn*(tot-2),sum+mn+mnn*(tot+1));
        }
      printf("%d
    ",ans);
      return 0;
    }
    bzoj 1697
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int const xn=1e6+5;
    int n,w[xn],t[xn],a[xn],b[xn],mn,sta[xn],tot,mnn;
    ll ans,sum;
    bool vis[xn];
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    void dfs(int x)
    {
      sta[++tot]=x; vis[x]=1; 
      mn=min(mn,w[x]); sum+=w[x];
      if(!vis[b[x]])dfs(b[x]);
    }
    int main()
    {
      n=rd(); mnn=6505;
      for(int i=1;i<=n;i++)t[i]=rd(),mnn=min(mnn,t[i]);
      for(int i=1,x;i<=n;i++)x=rd(),a[x]=i,w[i]=t[x];//
      for(int i=1,x;i<=n;i++)x=rd(),b[i]=a[x];
      for(int i=1;i<=n;i++)
        {
          if(vis[i])continue;
          tot=0; mn=6505; sum=0;
          dfs(i);
          ans+=min(sum+(ll)mn*(tot-2),sum+mn+(ll)mnn*(tot+1));
        }
      printf("%lld
    ",ans);
      return 0;
    }
    bzoj 1119
  • 相关阅读:
    ubuntu基本命令篇13用户管理
    网易邮箱繁体字信件乱码解决
    ubuntu基本命令篇16网络管理
    Ubuntu 10.04的安装
    DotNetNuke模块开发(一)
    查询进程打开的文件(转)
    Shell 的变量(转)
    Boot loader: Grub进阶(转)
    bash的通配符与特殊符号
    shell下的作业管理(转)
  • 原文地址:https://www.cnblogs.com/Zinn/p/10060557.html
Copyright © 2011-2022 走看看