【CodeForces】704 B. Ant Man

【题目】B. Ant Man

【题意】给定n个人的xi,ai,bi,ci,di,起点为s,终点为e,移动:

In simpler words, jumping from i-th chair to j-th chair takes exactly:

  • |xi?-?xj|?+?ci?+?bj seconds if j?<?i.
  • |xi?-?xj|?+?di?+?aj seconds otherwise (j?>?i).

求中间经过所有点恰好一次的最小代价。

【算法】动态规划

【题解】很巧妙的DP状态设计。(这样类似哈密顿路径的问题不能从图论方面考虑,否则很容易变成NP问题)

将代价拆分到每个点:

向左,起c+x,落b-x

向右,起d-x,落a+x

那么对于前i个点,有效信息只有这i个点中缺少多少入边和缺少多少出边。先无视s(起点)和t(终点),那么缺入边数和缺出边数相等。

令f[i][j]表示前i个点中缺少j条入/出边的最小代价,缺少入边的本质是被往左,缺少出边的本质是往右。

对于f[i-1][j],有以下四种转移:

被往右+往右:j>0,f[i][j]=f[i-1][j]+a[i]+d[i](两个x[i]抵消)——减少一条出边,同时增加一条出边

往左+被往左:j>0,f[i][j]=f[i-1][j]+b[i]+c[i]——减少一条入边,同时增加一条入边

被往右+往左:j>0,f[i][j-1]=f[i-1][j]+a[i]+c[i]+2*x[i]——减少一条入边和一条出边

往右+被往左:f[i][j+1]=f[i-1][j]+b[i]+d[i]-2*x[i]——增加一条入边和一条出边

最终答案为f[n][0]。

接下来解决s和t的问题,实际上s和t才能代表一个完整的点,所以将s当成一个完整的点,不把t看作一个点。

先经过s:会多一条不该有的入边,所以只要避免第二个和第三个转移。

先经过t:会少一条该有的入边,所以只要在j=0时强制进行第二个转移。

最后在到达n之前和st均有或均无时,不能成环,强制f[i][0]=inf。

复杂度O(n^2)。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll inf=1e16,maxn=5010;
ll f[maxn][maxn];
int n,s,t,x[maxn],a[maxn],b[maxn],c[maxn],d[maxn];
void m(ll &a,ll b){if(a>b)a=b;}
ll solve(){
    memset(f,0x3f,sizeof(f));
    int tot=0;f[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=i;j++)if(f[i-1][j]<inf){
            int S=j,T=S+tot;
            if(i==s){
                if(T)m(f[i][j],f[i-1][j]+c[i]+x[i]);
                m(f[i][j+1],f[i-1][j]+d[i]-x[i]);
            }
            else if(i==t){
                if(S)m(f[i][j-1],f[i-1][j]+a[i]+x[i]);
                m(f[i][j],f[i-1][j]+b[i]-x[i]);
            }
            else{
                if(S)m(f[i][j],f[i-1][j]+a[i]+d[i]);
                if(T)m(f[i][j],f[i-1][j]+b[i]+c[i]);
                if(S&&T)m(f[i][j-1],f[i-1][j]+a[i]+c[i]+2*x[i]);
                m(f[i][j+1],f[i-1][j]+b[i]+d[i]-2*x[i]);
            }
        }
        if(i==s)tot--;if(i==t)tot++;
        if(i!=n&&tot==0)f[i][0]=inf;
    }
    return f[n][0];
}
int main(){
    scanf("%d%d%d",&n,&s,&t);
    for(int i=1;i<=n;i++)scanf("%d",&x[i]);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)scanf("%d",&b[i]);
    for(int i=1;i<=n;i++)scanf("%d",&c[i]);
    for(int i=1;i<=n;i++)scanf("%d",&d[i]);
    printf("%lld",solve());
    return 0;
}

PS:我在这场比赛进行Virtual participation的时候,大力贪心出B……然后排名好高啊><。

至今无人能证明但AC了的贪心(似乎有人给反例):初始s-t,然后考虑一个一个点找最优位置插入。

原文地址:https://www.cnblogs.com/onioncyc/p/8277875.html

时间: 2024-11-08 21:49:46

【CodeForces】704 B. Ant Man的相关文章

【CodeForces】704 C. Black Widow 动态规划+模拟

[题目]C. Black Widow [题意]给定一个表达式,形式为(...)^(...)^......^(...)=1(n个括号),括号中为1~2个值取或.有m个变量,给出表达式的值为xi或 !xi,xi只能为0或1,求变量赋值使得表达式成立的方案数.每个变量至多出现两次.n,m<=10^5. [算法]动态规划+模拟 [题解]每个括号视为一个点,对于同时出现在两个括号内的变量将两个点连边(边须记两边异同).由于每个变量至多出现两次,所以一条边就可以代表一个变量. 由于每个括号至多两个变量,所以

【codeforces】【比赛题解】#854 CF Round #433 (Div.2)

cf一如既往挺丧 看丧题点我! [A]分数 Petya是数学迷,特别是有关于分数的数学.最近他学了所谓一个分数被叫做"真分数"当且仅当其分子小于分母,而一个分数被叫做"最简分数"当且仅当其分子分母互质.在闲暇时间,Petya在用计算器研究:如何把最简真分数转换为小数等问题.有一天他不小心把除号(÷)按成了加号(+),导致他得到了分子与分母的和.Petya想要得到他原来的分数,但他很快发现这不是唯一的.所以现在他想要知道最大的最简真分数使得其分子与分母的和为n. 输入

【CodeForces】835D Palindromic characteristics

[算法]区间DP [题解]涉及回文问题的区间DP都可以用类似的写法,就是h[i][j]表示i~j是否回文,然后就可以O(1)判断回文了. f[i][j]=k表示该字符串是k-th字符串,因为首先要求回文,既然回文那么左半边和右半边就肯定一样了. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=5010; int f[maxn][maxn]

【codeforces】【比赛题解】#849 CF Round #431 (Div.2)

cf的比赛越来越有难度了--至少我做起来是这样. 先看看题目吧:点我. 这次比赛是北京时间21:35开始的,算是比较良心. [A]奇数与结束 "奇数从哪里开始,又在哪里结束?梦想从何处起航,它们又是否会破灭呢?" 给定一个长度为n的序列.确定能不能将序列分成奇数个长度为奇数的非空字串,而且这其中每个子串以奇数开头,以奇数结尾.可以只分成一个(1也是奇数). 输入 第一行一个正整数n,表示序列长度. 第二行n个整数,表示序列中的元素. 输出 输出"Yes"或"

【CodeForces】841C. Leha and Function(Codeforces Round #429 (Div. 2))

[题意]定义函数F(n,k)为1~n的集合中选择k个数字,其中最小数字的期望. 给定两个数字集A,B,A中任意数字>=B中任意数字,要求重组A使得对于i=1~n,sigma(F(Ai,Bi))最大. [算法]数学结论+数学期望+排序 [题解]很无奈,这题放在div2 C,难以推导的期望公式,广为人知的结论,容易观察样例得出的做法,都体现了这道题的不合理性. F(n,k)=(n+1)/(k+1) 公式推导可能触及我的知识盲区了QAQ 得到公式后,显然要求k尽可能小,n尽可能大,经验告诉我们随着两数

【CodeForces】585 E. Present for Vitalik the Philatelist

[题目]E. Present for Vitalik the Philatelist [题意]给定n个数字,定义一种合法方案为选择一个数字Aa,选择另外一些数字Abi,满足?gcd(Aa,Abi)=1,且gcd(Ab1...Abx)≠1,求方案数取模1e9+7.2<=n<=5*10^5,2<=ai<=10^7. [算法]数论,计数问题 [题解]

【CodeForces】578 C. Weakness and Poorness

[题目]C. Weakness and Poorness [题意]给定含n个整数的序列ai,定义新序列为ai-x,要使新序列的最大子段和绝对值最小,求实数x.n<=2*10^5. [算法]二分||三分||计算几何(凸包) [题解]Editorial 令正数最大子段和为A,负数最大子段和为B,绝对值是max(A,B).当x从小到大变化时,A由大变小,B由小变大. 容易发现这是一个下凸函数,可以用三分法求解. 但是,这道题卡精度(-11会WA,-12会T),解决方法是根据复杂度把循环次数卡到极限而不

【CodeForces】F. Letters Removing

[题目]F. Letters Removing [题意]给定只含小写字母.大写字母和数字的字符串,每次给定一个范围要求删除[l,r]内的字符c(l和r具体位置随删除变动),求m次操作后的字符串.n<=2*10^5. [算法]树状数组+平衡树(set) [题解]因为坐标是序列变动后的,动态坐标可以转化为找到第l个存在的数字到第r个存在的数字之间的范围. 将序列中存在记为1,删除记为0,转化为找前缀和恰好为l和r的位置,这是树状数组的经典操作,详见这篇题解介绍的方法(简单的排名功能) 找到l和r在原

【CodeForces】D. Roads in Yusland

[题目]D. Roads in Yusland [题意]给定n个点的树,m条严格从下往上的路径,每条路径代价ci,求最少代价使得路径覆盖所有边.n,m<=3*10^5,ci<=10^9. [算法]树形DP+线段树||可并堆 [题解]