zoukankan      html  css  js  c++  java
  • JOISC 2014 邮戳拉力赛(DP)

    题意

    https://loj.ac/problem/2878

    思路

    真的神仙题,想到就很好写,想不到就写不出来。

    肯定只能一个一个邮戳按顺序分析。首先,将取一枚邮戳的路径分为四种:

    • 上行 ( ightarrow) 邮戳台 ( ightarrow) 上行 简称路径 ((U,V))
    • 上行 ( ightarrow) 邮戳台 ( ightarrow) 下行 简称路径 ((U,E))
    • 下行 ( ightarrow) 邮戳台 ( ightarrow) 下行 简称路径 ((D,E))
    • 下行 ( ightarrow) 邮戳台 ( ightarrow) 上行 简称路径 ((D,V))

    取一枚邮戳也就这四种路径。

    但我们发现,路径 ((D,V)) 的出现前提是有路径 ((U,E)) 在前面出现过,也就是说到任意一个点路径 ((U,E)) 的条数总是多余路径 ((D,V)) 。也是说,我们可以将 ((U,E)) 的条数减 ((D,V)) 的条数当 ( ext{dp}) 的第二维,也就是还未抵消的 ((U,E)) 路径。另外 ((D,V)) 路径出现的条件为至少有一个还未抵消的 ((U,E)) 路径。

    那么转移就是上述的四种,一个 (O(n^3)) 的暴力很快就能出来了

    chk_min(dp[i][j],dp[i-1][j]+u+v);
    if(j>0)chk_min(dp[i][j],dp[i-1][j]+d+e);
    FOR(k,1,j)chk_min(dp[i][j],dp[i-1][j-k]+(d+v)*k);
    FOR(k,1,n-j)chk_min(dp[i][j],dp[i-1][j+k]+(u+e)*k);
    dp[i][j]+=(ll)T*(2*j+1);	//计算j个(D,V)路径的贡献 
    

    不难发现后面两维可以直接前后缀优化,或者背包转移,复杂度就优化至 (O(n^2)) 了。

    代码

    #include<bits/stdc++.h>
    #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
    #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
    using namespace std;
    template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
    template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
    typedef long long ll;
    const int N=3005;
    ll dp[N][N],f[N],g[N];
    int n,T;
    
    int main()
    {
    	scanf("%d%d",&n,&T);
    	memset(dp,0x3f,sizeof(dp));
    	dp[0][0]=0;
    	FOR(i,1,n)
    	{
    		int u,v,d,e;
    		scanf("%d%d%d%d",&u,&v,&d,&e);
    		FOR(j,0,n)f[j]=g[j]=dp[i-1][j];
    		FOR(j,1,n)chk_min(f[j],f[j-1]+(d+v));
    		DOR(j,n-1,0)chk_min(g[j],g[j+1]+(u+e));
    		FOR(j,0,n)
    		{
    			chk_min(dp[i][j],dp[i-1][j]+u+v);
    			if(j>0)chk_min(dp[i][j],dp[i-1][j]+d+e);
    //			FOR(k,1,j)chk_min(dp[i][j],dp[i-1][j-k]+(d+v)*k);
    //			FOR(k,1,n-j)chk_min(dp[i][j],dp[i-1][j+k]+(u+e)*k);
    			if(j>0)chk_min(dp[i][j],f[j-1]+(d+v));
    			if(j<n)chk_min(dp[i][j],g[j+1]+(u+e));
    			dp[i][j]+=(ll)T*(2*j);
    		}
    	}
    	printf("%lld
    ",dp[n][0]+(n+1)*T);
    	return 0;
    }
    
  • 相关阅读:
    如何用SQL命令修改字段名称
    两个sql server 2000的通用分页存储过程
    Tomcat 6 连接 MS SQL 2005
    log4net 配置与应用
    如何去除Google搜索结果病毒提示
    Windows 2003远程桌面连接数限制
    ntext replace sql
    FCKeditor详细的设置
    SQL Server 自增字段归零等问题
    SQLServer2005数据库还原到SQLServer2000
  • 原文地址:https://www.cnblogs.com/Paulliant/p/10256813.html
Copyright © 2011-2022 走看看