标签:
题目:有一栋楼,每层楼上有t个人打网球,有p个人游泳,但是每层只能建一种健身设施。每个人的花费是他到最近的对应设施的楼层距离。问最小总花费。
思路:dp[i][j][k]表示做到第i层的时候选j,和j不同的设施最近在第k层的最小花费,那么如果该层选得和上面一样那么k不变,这个好转移。如果和上一层不一样,那么k层到当前层i的玩家会有一部分重新分布(他们的选择显然以中点为准),这个需要预处理一下(我写得很恶心。。。)。然后wa了整整一天,最后找了个代码对拍了一下才过(基本上完全是对的,,有个初始化没做。。。真是哔了狗。。)。这个对拍器真是好使啊。。。。
丑陋的代码。。
/* * @author: Cwind */ #include <bits/stdc++.h> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-10) #define IINF (1<<29) #define LINF (1ll<<49) #define INF (1000000300) #define FINF (1e9) #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) #define mset(x,v) memset((x),(v),sizeof (x)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; const int maxn=5000; int T; int n; ll t[maxn],p[maxn]; ll ts[2][maxn],ps[2][maxn]; ll tmm[2][maxn],pm[2][maxn]; ll dp[2][2][maxn]; void cal(){ for(int i=1;i<=n;i++){ ts[0][i]=ts[0][i-1]+t[i]; ps[0][i]=ps[0][i-1]+p[i]; tmm[0][i]=tmm[0][i-1]+t[i]*i; pm[0][i]=pm[0][i-1]+p[i]*i; } ts[1][n+1]=ps[1][n+1]=0; tmm[1][n+1]=pm[1][n+1]=0; for(int i=n;i>=1;i--){ ts[1][i]=ts[1][i+1]+t[i]; ps[1][i]=ps[1][i+1]+p[i]; tmm[1][i]=tmm[1][i+1]+t[i]*(n-i+1); pm[1][i]=pm[1][i+1]+p[i]*(n-i+1); } } ll get(bool o,int l,int r){ int m=(r+l)/2; if(o){ if(l==0) return tmm[1][1]-tmm[1][r+1]-(ts[1][1]-ts[1][r+1])*(n-r+1); ll oc=tmm[0][r]-tmm[0][l-1]-(ts[0][r]-ts[0][l-1])*l; ll nc=tmm[0][m]-tmm[0][l-1]-(ts[0][m]-ts[0][l-1])*l+tmm[1][m+1]-tmm[1][r+1] -(ts[1][m+1]-ts[1][r+1])*(n-r+1)+t[r]*(r-l); return nc-oc; }else{ if(l==0) return pm[1][1]-pm[1][r+1]-(ps[1][1]-ps[1][r+1])*(n-r+1); ll oc=pm[0][r]-pm[0][l-1]-(ps[0][r]-ps[0][l-1])*l; ll nc=pm[0][m]-pm[0][l-1]-(ps[0][m]-ps[0][l-1])*l+pm[1][m+1]-pm[1][r+1] -(ps[1][m+1]-ps[1][r+1])*(n-r+1)+p[r]*(r-l); return nc-oc; } } int cas; int main(){ //freopen("/home/slyfc/CppFiles/in","r",stdin); //freopen("/home/slyfc/CppFiles/out","w",stdout); cin>>T; while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%lld%lld",&t[i],&p[i]); cal(); for(int i=0;i<2;i++) for(int k=0;k<2;k++) for(int j=0;j<maxn;j++) dp[i][k][j]=LINF; dp[0][0][0]=dp[0][1][0]=0; dp[1][0][0]=dp[1][1][0]=0; bool f=0; for(int i=2;i<=n;i++){ f^=1; for(int j=1;j<i-1;j++){ dp[f][0][j]=dp[f^1][0][j]+p[i]*(i-j); dp[f][1][j]=dp[f^1][1][j]+t[i]*(i-j); } for(int j=0;j<i-1;j++){ dp[f][0][i-1]=min(dp[f][0][i-1],dp[f^1][1][j]+p[i]+get(1,j,i)); dp[f][1][i-1]=min(dp[f][1][i-1],dp[f^1][0][j]+t[i]+get(0,j,i)); } } ll ans=LINF; for(int i=1;i<n;i++){ ans=min(ans,dp[f][1][i]); ans=min(ans,dp[f][0][i]); } printf("Case #%d: %lld\n",++cas,ans); } return 0; }
对拍器
while true; do ./make>inData #出数据 ./myCpp<inData>myOut #被测程序 ./stdCpp<inData>stdOut #正确(暴力)程序 if diff myOut stdOut; then #比较两个输出文件 printf AC #结果相同显示AC else echo WA #结果不同显示WA,并退出 #cat tmp.out tmp2.out exit 0 fi #if的结束标志,与C语言相反,0为真 done # while的结束标志 #BY NICK WONG 2014-08-29 #在终端下,进入当前目录,输入"sh ./nick.sh",(其中nick.sh为当前shell脚本名) ‘#‘表示单行注释 #diff在两文件相同时返回空串
对拍器转自:http://blog.csdn.net/nickwong_/article/details/38931579
标签:
原文地址:http://www.cnblogs.com/Cw-trip/p/4924271.html