• CF536D Tavas in Kansas


    题目

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

    不妨再假设一个在((0,0))处的点,两个人轮流移动这个点,( m Tavas)只能向右移动,( m Nafas)只能向上移动,每次移动必须框住新的点,这样到最后得到一个阶梯状的图形,这个范围里就是( m 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;
    }
    
    
  • 相关阅读:
    win10 uwp iot
    app已损坏,打不开。你应该将它移到废纸篓
    DIVCNT2&&3
    win10 uwp iot
    win10 uwp 屏幕常亮
    win10 uwp 屏幕常亮
    win10 uwp 使用油墨输入
    win10 uwp 使用油墨输入
    win10 UWP 全屏
    win10 UWP 全屏
  • 原文地址:https://www.cnblogs.com/asuldb/p/12015363.html
Copyright © 2020-2023  润新知