RQNOJ 496
/* dp记录路径的问题 f[i][j]表示用前j个花瓶盛放前i朵花的最大值 */ #include<cstdio> #include<iostream> #include<cstring> #define N 110 #define INF 1000000000 using namespace std; int a[N][N],f[N][N],q[N],n,m; int main() { memset(f,-127/3,sizeof(f)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); f[0][0]=0; for(int i=1;i<=n;i++) for(int j=i;j<=m;j++) for(int k=i-1;k<j;k++) f[i][j]=max(f[i-1][k]+a[i][j],f[i][j]); int ans=-INF,pos; for(int i=n;i<=m;i++) if(f[n][i]>ans) { ans=f[n][i];pos=i; } printf("%d ",ans); q[n]=pos; int x=n; while(x--) { for(int i=1;i<pos;i++) if(f[x][i]==ans-a[x+1][pos]) { q[x]=i;ans-=a[x+1][pos];pos=i; break; } } for(int i=1;i<=n;i++)printf("%d ",q[i]); return 0; }
tyvj 1313
/* 朴素的动规很好想,f[i]表示选前i个且第i个必选的最小值。f[i]=f[j]+a[i] 因为可以选的j来自一段固定长度的区间,并且我们每次要选最小值,所以可以用单调队列优化。 */ #include<iostream> #include<cstring> #include<cstdio> #define N 1000010 #define inf 2100000000 using namespace std; int n,m,head,tail,Min; int q[N],a[N],f[N]; int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++) { while (q[head]<i-m&&head<=tail) head++; f[i]=a[i]+f[q[head]]; while (f[q[tail]]>f[i]&&head<=tail) tail--; q[++tail]=i; } Min=inf; for (int i=n-m+1;i<=n;++i) Min=min(Min,f[i]); printf("%d ",Min);
}
洛谷 1650
/* 虽说是dp,但总觉得有些贪心的思想在里面 因为我们尽量要把齐王的跑得慢的马比下去,而且要尽量用田忌的马中比较慢的。 所以先排一遍序,然后当当前田忌的马慢时,换下一匹,如果一样快,可以换下一匹,也可以这样比,如果快,就比。 */ #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define N 2016 #define inf 100000000 using namespace std; int a[N],b[N],f[N][N],n,ans=-inf; int dfs(int x,int y) { if(f[x][y]!=-1)return f[x][y]; if(x>n)return 0; if(a[x]<b[y])f[x][y]=dfs(x+1,y)-200; else if(a[x]==b[y]) f[x][y]=max(dfs(x+1,y)-200,dfs(x+1,y+1)); else f[x][y]=dfs(x+1,y+1)+200; return f[x][y]; } int main() { freopen("jh.in","r",stdin); memset(f,-1,sizeof(f)); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&b[i]); sort(a+1,a+n+1);sort(b+1,b+n+1); printf("%d",dfs(1,1)); return 0; }
洛谷 1594
/* 80分,有两个数据爆了double了,没有过 记忆化搜索,很好理解。 f[x][y]表示通过前x辆车,且第x辆车所属车队以y开头的最少时间 */ #include<cstdio> #include<iostream> #include<cstring> #define N 1010 using namespace std; int w[N],n,zz;double f[N][N],t[N],s,ans=100000000.0; double query(int x,int y)//数据较弱,懒得写rmq了 { double maxn=0; for(int i=x;i<=y;i++) maxn=max(maxn,t[i]); return maxn; } double dfs(int x,int y) { if(f[x][y]!=-1.0)return f[x][y]; if(x>n)return 0; if(w[x+1]-w[y-1]<=zz&&x<n) f[x][y]=min(dfs(x+1,y),dfs(x+1,x+1)+query(y,x)); else f[x][y]=dfs(x+1,x+1)+query(y,x); return f[x][y]; } int main() { scanf("%d%lf%d",&zz,&s,&n); for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) f[i][j]=-1.0; for(int i=1;i<=n;i++) { double v;scanf("%d%lf",&w[i],&v); t[i]=s*60/v;w[i]+=w[i-1]; } printf("%.1lf",dfs(1,1)); return 0; }