CF536D Tavas in Kansas

题目

跑两遍最短路显然是必须的,于是对于每个点\(i\)我们得到了到\(s\)的最短路\(dis_{0,i}\)和到\(t\)的最短路\(dis_{1,i}\),不妨将其看做二维平面上一个坐标为\((dis_{0,i},dis_{1,i})\)的点

不妨再假设一个在\((0,0)\)处的点,两个人轮流移动这个点,\(\rm Tavas\)只能向右移动,\(\rm Nafas\)只能向上移动,每次移动必须框住新的点,这样到最后得到一个阶梯状的图形,这个范围里就是\(\rm Tavas\)的得分

于是我们可以搞一个\(dp\),就是在哪个位置,这一步应该由谁来走,转移的时候需要一个后缀最值来优化,同时记得判断这个转移是否能框住新的点;

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#define mp std::make_pair
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const LL inf=1e15;const int maxn=2e3+5;
inline int read() {
    char c=getchar();int x=0,r=1;while(c<'0'||c>'9') {if(c=='-') r=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x*r;
}
int n,m,s,t,p[maxn],vis[maxn],N,M;
struct E{int v,nxt,w;}e[200005];
int head[maxn],num,ri[maxn],rj[maxn],cnt[maxn][maxn];LL dis[2][maxn],A[maxn];
LL pre[maxn][maxn],dp[maxn][maxn][2],mn[maxn][maxn],mx[maxn][maxn],sum;
typedef std::pair<LL,int> pii;
std::priority_queue<pii,std::vector<pii>,std::greater<pii> > q;
inline void add(int x,int y,int w){e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].w=w;}
inline void Dij(LL *d,int S) {
    for(re int i=1;i<=n;i++) vis[i]=0,d[i]=inf;
    d[S]=0;q.push(mp(0,S));
    while(!q.empty()) {
        int k=q.top().second;q.pop();
        if(vis[k]) continue;vis[k]=1;
        for(re int i=head[k];i;i=e[i].nxt)
            if(d[e[i].v]>d[k]+e[i].w) d[e[i].v]=d[k]+e[i].w,q.push(mp(d[e[i].v],e[i].v));
    }
}
inline void upd(int i,int j) {
    mn[i][j]=min(dp[i][j][1],mn[i][j+1]);
    mx[i][j]=max(dp[i][j][0]+pre[i][j+1],mx[i+1][j]);
}
signed main() {
    n=read(),m=read(),s=read(),t=read();
    for(re int i=1;i<=n;i++) p[i]=read(),sum+=p[i];
    for(re int x,y,z,i=1;i<=m;i++) {
        x=read(),y=read(),z=read();
        add(x,y,z),add(y,x,z);
    }
    Dij(dis[0],s),Dij(dis[1],t);
    for(re int i=1;i<=n;i++) A[i]=dis[0][i];
    std::sort(A+1,A+n+1);N=std::unique(A+1,A+n+1)-A-1;
    for(re int i=1;i<=n;i++) dis[0][i]=std::lower_bound(A+1,A+n+1,dis[0][i])-A;
    for(re int i=1;i<=n;i++) A[i]=dis[1][i];
    std::sort(A+1,A+n+1);M=std::unique(A+1,A+n+1)-A-1;
    for(re int i=1;i<=n;i++) dis[1][i]=std::lower_bound(A+1,A+n+1,dis[1][i])-A;
    for(re int i=1;i<=n;i++) pre[dis[0][i]][dis[1][i]]+=p[i],cnt[dis[0][i]][dis[1][i]]++;
    for(re int i=1;i<=N+1;i++) for(re int j=M+1;j>=0;j--) pre[i][j]+=pre[i][j+1];
    for(re int i=1;i<=N+1;i++) for(re int j=0;j<=M+1;j++) pre[i][j]+=pre[i-1][j];
    for(re int i=N+1;i>=0;i--) for(re int j=M+1;j>=0;j--) cnt[i][j]+=cnt[i][j+1];
    for(re int i=N+1;i>=0;i--) for(re int j=M+1;j>=0;j--) cnt[i][j]+=cnt[i+1][j];
    memset(rj,-1,sizeof(rj));memset(ri,-1,sizeof(ri));
    memset(mx,-20,sizeof(mx));memset(mn,20,sizeof(mn));
    for(re int i=N;i>=0;i--)
        for(re int j=M;j>=0;--j) {
            if(cnt[i+1][j+1]==0) {dp[i][j][0]=dp[i][j][1]=0;upd(i,j);continue;}
            if(cnt[i+1][j+1]>cnt[i+1][j+2]) ri[i]=j+1;
            if(ri[i]!=-1) dp[i][j][0]=mn[i][ri[i]];else dp[i][j][0]=-inf;
            if(cnt[i+1][j+1]>cnt[i+2][j+1]) rj[j]=i+1;
            if(rj[j]!=-1) dp[i][j][1]=mx[rj[j]][j]-pre[i][j+1];else dp[i][j][1]=inf;
            upd(i,j);
        }
    if(sum-dp[0][0][1]==dp[0][0][1]) puts("Flowers");
    if(sum-dp[0][0][1]>dp[0][0][1]) puts("Cry");
    if(sum-dp[0][0][1]<dp[0][0][1]) puts("Break a heart");
    return 0;
}
上一篇:【AtCoder】AtCoder Grand Contest 031 解题报告($A\sim E$)


下一篇:RI AF R A学习笔记