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 ",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 ",ans); }