USACO 2016 February Contest, Gold解题报告

1.Circular Barn 

 http://www.usaco.org/index.php?page=viewproblem2&cpid=621

贪心

#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
long long sum(long long v) 
{
  return v*(v+1)*(2*v+1)/6;
}
int main() 
{
      int N,c=0;
      scanf("%d",&N);
      vector<long long> A(N);
      for(int i=0;i<N;i++) 
    {
        scanf("%d",&A[i]);
        c=max(0ll,c+A[i]-1);
      }
      for(int i=0;;i++) 
    {
        if(c==0) 
        {
              rotate(A.begin(),A.begin()+i,A.begin()+N);
              break;
        }
        c=max(0ll,c+A[i]-1);
      }
      long long res=0;
      for (int i=0;i<N;i++) 
    {
        res+=sum(A[i]+c-1)-sum(c-1);
        c=max(0ll,c+A[i]-1);
      }
      printf("%d",res);
}

2.Circular Barn Revisited

http://www.usaco.org/index.php?page=viewproblem2&cpid=622

首先,记录从i开始的j个房间的奶牛都从i从i号门进入所走的总距离。

然后进行dp,找出最小路程

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100
#define MAXK 7
int n,r[MAXN+10],k;
long long f[MAXN*2+1][MAXN+1][MAXK+1],ans=0x7fffffffffffffffll,dist[MAXN+10][MAXN+10];
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
void read(){
    Read(n),Read(k);
    int i;
    for(i=1;i<=n;i++)
        Read(r[i]);
}
void prepare(){
    int i,j;
    for(i=1;i<=n;i++){
        dist[i][1]=0;
        for(j=2;j<=n;j++)
            dist[i][j]=r[(i+j-2)%n+1]*(j-1)+dist[i][j-1];
    }
}
void dp(){
    int i,j,l,t=2*n,p;
    memset(f,0x3f,sizeof f);
    for(i=0;i<=t;i++)
        f[i][0][0]=0;
    for(i=1;i<=n;i++){
        for(j=1;j<=n&&j<=i;j++)
            for(l=1;l<=k;l++)
                for(p=1;p<=j;p++)
                    f[i][j][l]=min(f[i][j][l],f[i-p][j-p][l-1]+dist[i-p+1][p]);
        ans=min(ans,f[i][n][k]);
    }
    for(i=n+1;i<=t;i++){
        for(j=1;j<=n;j++)
            for(l=1;l<=k;l++)
                for(p=1;p<=j;p++)
                    f[i][j][l]=min(f[i][j][l],f[i-p][j-p][l-1]+dist[(i-p)%n+1][p]);
        ans=min(ans,f[i][n][k]);
    }
}
int main()
{
    read();
    prepare();
    dp();
    printf("%lld\n",ans);
}

3.Fenced In

最小生成树

处理出连通块之间栅栏的长度然后做最小生成树即可。 但是这样会T,尽管算法时间复杂度为 O(n2log2n) 

优化:由于每一行或每一列中的相邻两个连通块之间的栅栏长度相等,我们可以考虑使用kruskal算法,仅仅对每两个栅栏之间的距离排序,然后然后再对这一行(列)的所有相邻连通块连边即可。 

#include<cstdio>
#include<algorithm>
#define MAXN 2000
using namespace std;
long long ans;
int n,a[MAXN+10],b[MAXN+10],A,B,m,tot,fa[(MAXN+1)*(MAXN+1)+10];
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
void read(){
    int i,t;
    Read(A),Read(B),Read(n),Read(m);
    for(i=1;i<=n;i++)
        Read(a[i]);
    for(i=1;i<=m;i++)
        Read(b[i]);
    sort(a+1,a+n+1);
    sort(b+1,b+m+1);
    a[++n]=A;
    b[++m]=B;
    for(i=n;i;i--)
        a[i]-=a[i-1];
    for(i=m;i;i--)
        b[i]-=b[i-1];
    sort(a+1,a+n+1);
    sort(b+1,b+m+1);
    t=n*m;
    for(i=1;i<=t;i++)
        fa[i]=i;
}
int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
void kruskal(){
    int i,j,k,l;
    i=j=1;
    while(i<=n||j<=m){
        if(j>m||(i<=n&&a[i]<=b[j])){
            k=(i-1)*m+1;
            for(l=1;l<m;l++,k++)
                if(find(k)!=find(k+1))
                    fa[fa[k]]=fa[k+1],ans+=a[i];
            ++i;
        }
        else{
            k=j;
            for(l=1;l<n;l++,k+=m)
                if(find(k)!=find(k+m))
                    fa[fa[k]]=fa[k+m],ans+=b[j];
            ++j;
        }
    }
}
int main()
{
    read();
    kruskal();
    printf("%lld\n",ans);
}
View Code

猜你喜欢

转载自www.cnblogs.com/wisdom-jie/p/9302723.html