1 条题解

  • 0
    @ 2026-5-3 12:24:02

    前言:

    本题解重点不在代码写法,而在于结论为何有正确性。

    思路分析:

    O(nm)O(nm) 的朴素 DP 求出每个 gi,jg_{i,j} 是简单的,增加一维 0/10/1 表示轮到谁行动了:

    gi,j,0=min(gi,j+1,1,gi+1,j,1)g_{i,j,0}=\min(g_{i,j+1,1},g_{i+1,j,1}) gi,j,1=max(gi,j+1,0,gi+1,j,0)g_{i,j,1}=\max(g_{i,j+1,0},g_{i+1,j,0})

    最终 ans=gi,j,0ans=\sum g_{i,j,0}

    代入得:

    $$g_{i,j,0}=\min(\max(g_{i+1,j+1,0},g_{i+2,j+1,0}),\max(g_{i+1,j+1,0},g_{i,j+2,0}))$$$$=\max(g_{i+1,j+1,0},\min(g_{i+2,j,0},g_{i,j+2,0}))$$

    那么就可以将增加的一维状态删去了:

    $$g_{i,j}=\max(g_{i+1,j+1},\min(g_{i+2,j},g_{i,j+2}))$$

    观察式子发现 gi,jgi+1,j+1g_{i,j}\ge g_{i+1,j+1}。深入观察转移方程,可以发现 gi,jg_{i,j} 一定由 gi+1,j+1g_{i+1,j+1} 转移而来。

    假设 gi,jg_{i,j}gi+2,jg_{i+2,j} 转移,那么再次考虑 gi+2,jg_{i+2,j} 可以由三种情况转移得到:

    • gi+2,j+2gi+2,jgi,jg_{i+2,j+2}\to g_{i+2,j}\to g_{i,j} 等价于 gi+2,j+2gi+1,j+1gi,jg_{i+2,j+2}\to g_{i+1,j+1}\to g_{i,j},不考虑。
    • gi+3,j+1gi+2,jgi,jg_{i+3,j+1}\to g_{i+2,j}\to g_{i,j} 等价于 gi+3,j+1gi+1,j+1gi,jg_{i+3,j+1}\to g_{i+1,j+1}\to g_{i,j},不考虑。
    • gi+4,jgi+2,jgi,jg_{i+4,j}\to g_{i+2,j}\to g_{i,j},考虑一下,先手和后手一直向右走,向右既能最小化游戏目标,又能最大化?不合理,也就是说这种情况已经在不断的取 min\minmax\max 的过程中非法了。

    那么得出结论,gi,j=gi+1,j+1g_{i,j}=g_{i+1,j+1}。感性理解一下结论,即连续两次移动先手和后手一定会选择不同的方向,最终走出一条折线。这具有优雅的正确性,因为一个方向更大化,另一个方向就是更小化。

    所以对于一般的情况我们简化为了 gi,j=gi+1,j+1g_{i,j}=g_{i+1,j+1}。再预处理一下可以一轮进洞的情况就可将 dpdp 放在斜率为 π4\frac{\pi}{4} 的独立的斜线上进行。由于洞的数量非常少,我们仅需要知道哪里的 gg 改变了,连续一段贡献相同。

    AC Code:

    #include<bits/stdc++.h>
    #define int long long
    #define fi first
    #define se second
    using namespace std;
    const int mod=998244353;
    int n,m,k,ans;
    vector<pair<int,int>>v;
    map<pair<int,int>,int>w;
    map<int,int>f,p;
    bool cmp(pair<int,int>p,pair<int,int>q){return p>q;}
    void solve(bool o){
    	f.clear(),p.clear();
    	for(auto t:v){
    		int x=t.fi,y=t.se,i=x-y;
    		if((i&1)==o&&p.count(i))ans=(ans%mod+f[i]*(p[i]-x)%mod+mod)%mod;
    		if(w.count({x,y}))f[i]=w[{x,y}];
    		else f[i]=(i&1)==o?min(f[i-1],f[i+1]):max(f[i-1],f[i+1]);
    		p[i]=x;
    	}
    	for(auto t:f)if((t.fi&1)==o)
    		ans=(ans%mod+t.se*min(p[t.fi],p[t.fi]-t.fi)%mod+mod)%mod;
    }
    signed main(){
    	ios::sync_with_stdio(0);
    	cin.tie(0),cout.tie(0);
    	cin>>n>>m>>k;
    	for(int i=1,x,y,c;i<=k;i++){
    		cin>>x>>y>>c,w[{x,y}]=c;
    		for(int X=0;X<=2;X++)
    			for(int Y=0;X+Y<=2;Y++)
    				if(X<x&&Y<y)v.push_back({x-X,y-Y});
    	}
    	sort(v.begin(),v.end(),cmp);
    	v.erase(unique(v.begin(),v.end()),v.end());
    	solve(0),solve(1);
    	cout<<ans;
    	return 0;
    }
    

    完结撒花!!!

    • 1

    「ROI 2019 Day2」机器人高尔夫球赛

    信息

    ID
    10078
    时间
    3000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者