zoukankan      html  css  js  c++  java
  • 【CF536D】Tavas in Kansas(博弈+动态规划)

    点此看题面

    • 给定一张(n)个点(m)条边的无向图,每个点有一个点权(可能为负),每条边有一个长度。
    • 两名玩家分别处于(A,B)两点,轮流操作,每次指定一个距离(x),获得到他距离不超过(x)的所有未被获得过的点权(至少要包含一个未被获得过的点),直至所有点都被获得过。
    • 最终获得点权大的人胜,判断谁有必胜策略或平局。
    • (nle2 imes10^3,mle10^5)

    最短路+离散化

    首先我们肯定需要先预处理出(A,B)两点到所有点的距离,直接(Dijkstra)即可。

    注意距离可能很大,但那些没有点的距离显然是无用的,因此完全可以对(A,B)两点到所有点的距离分别离散化,使得距离全在([1,n])范围内。

    博弈论+动态规划

    这种问题常见的套路应该是维护先手权值与后手权值之差,那么先手就是要最大化这个差值,后手就是要最小化这个差值。

    由于一个人选的距离只能越来越大(因为如果距离小了必然所有点都已被获得过),所以有用的信息只有两人最后选择的距离。

    这样一来就可以建出一个二维平面,每个点根据到(A,B)两点的距离表示为二维平面上一个点((dA_i,dB_i)),点权为(a_i),并给点数和点权分别做一个二维前缀和命名为(c_{i,j})(s_{i,j})

    于是设(f_{0/1,i,j})表示现在轮到先手/后手操作,两人上次操作分别选择了距离(i,j)

    根据博弈论的经典套路,我们从最终状态向初始状态(f_{0,0,0})转移,转移式为:(对于最终状态直接赋值为(0)

    [f_{0,i,j}=max{f_{1,i',j}+s_{i+1,j+1}-s_{i'+1,j+1}|c_{i+1,j+1} ot=c_{i'+1,j+1}}\ f_{1,i,j}=min{f_{0,i,j'}-s_{i+1,j+1}+s_{i+1,j'+1}|c_{i+1,j+1} ot=c_{i+1,j'+1}} ]

    式子中的(s_{i+1,j+1})可以直接提出,然后就会发现剩余项中其实并没有同时与(i,i')或同时与(j,j')有关的项。

    又由于同一列和同一行的(c_{i,j})都具有单调性,我们可以对每一列和每一行分别开一个指针维护可转移的最小位置,并分别维护最大值/最小值便于转移。(其实就是特殊的双指针)

    最后只要判断(f_{0,0,0})的符号即可。

    代码:(O(n^2+mlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 2000
    #define M 100000
    #define LL long long
    #define Pr pair<LL,int>
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    #define Gmin(x,y) (x>(y)&&(x=(y)))
    #define add(x,y,z) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].v=z)
    using namespace std;
    int n,m,A,B,a[N+5],ee,lnk[N+5];struct edge {int to,nxt,v;}e[2*M+5];
    int dA[N+5],dB[N+5],c[N+5][N+5];LL s[N+5][N+5];
    namespace Dij//最短路
    {
    	int dc,vis[N+5];LL dis[N+5],dv[N+5];priority_queue<Pr,vector<Pr>,greater<Pr> > q;
    	I void Solve(CI s,int* d)
    	{
    		RI i,k;for(i=1;i<=n;++i) dis[i]=1e18,vis[i]=0;q.push(make_pair(dis[s]=0,s));
    		W(!q.empty()) if(k=q.top().second,q.pop(),!vis[k]) for(vis[k]=1,i=lnk[k];i;i=e[i].nxt)//Dijkstra
    			dis[k]+e[i].v<dis[e[i].to]&&(q.push(make_pair(dis[e[i].to]=dis[k]+e[i].v,e[i].to)),0);
    		for(i=1;i<=n;++i) dv[i]=dis[i];sort(dv+1,dv+n+1),dc=unique(dv+1,dv+n+1)-dv-1;
    		for(i=1;i<=n;++i) d[i]=lower_bound(dv+1,dv+dc+1,dis[i])-dv;//离散化
    	}
    }
    namespace DP//动态规划
    {
    	int p[N+5],q[N+5];LL u[N+5],v[N+5],f[2][N+5][N+5];
    	I void Solve()
    	{
    		RI i,j;for(i=0;i<=n;++i) p[i]=q[i]=n,u[i]=-1e18,v[i]=1e18;
    		for(i=n;~i;--i) for(j=n;~j;--j)//从最终状态向最初状态
    		{
    			W(c[p[j]+1][j+1]^c[i+1][j+1]) Gmax(u[j],f[1][p[j]][j]-s[p[j]+1][j+1]),--p[j];//维护列的指针和最大值
    			W(c[i+1][q[i]+1]^c[i+1][j+1]) Gmin(v[i],f[0][i][q[i]]+s[i+1][q[i]+1]),--q[i];//维护行的指针和最小值
    			f[0][i][j]=p[j]^n?u[j]+s[i+1][j+1]:0,f[1][i][j]=q[i]^n?v[i]-s[i+1][j+1]:0;//DP转移,最终状态为0
    		}
    		puts(f[0][0][0]?(f[0][0][0]>0?"Break a heart":"Cry"):"Flowers");//判断符号
    	}
    }
    int main()
    {
    	RI i,j,x,y,z;for(scanf("%d%d%d%d",&n,&m,&A,&B),i=1;i<=n;++i) scanf("%d",a+i);
    	for(i=1;i<=m;++i) scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
    	for(Dij::Solve(A,dA),Dij::Solve(B,dB),i=1;i<=n;++i) ++c[dA[i]][dB[i]],s[dA[i]][dB[i]]+=a[i];//根据距离表示到二维平面上
    	for(i=n;~i;--i) for(j=n;~j;--j) c[i][j]+=c[i+1][j],s[i][j]+=s[i+1][j];//二维前缀和(包括下一行)
    	for(i=n;~i;--i) for(j=n;~j;--j) c[i][j]+=c[i][j+1],s[i][j]+=s[i][j+1];return DP::Solve(),0; 
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    相机
    播放音乐
    录音
    NSURLConnection下载
    UITableView
    UIPageControl
    UIScrollView
    ajax禁止浏览器缓存
    java替换word2003
    退出登录
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF536D.html
Copyright © 2011-2022 走看看