1 条题解
-
0
前言:
本题解重点不在代码写法,而在于结论为何有正确性。
思路分析:
的朴素 DP 求出每个 是简单的,增加一维 表示轮到谁行动了:
最终 。
代入得:
$$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}))$$观察式子发现 。深入观察转移方程,可以发现 一定由 转移而来。
假设 由 转移,那么再次考虑 可以由三种情况转移得到:
- 等价于 ,不考虑。
- 等价于 ,不考虑。
- ,考虑一下,先手和后手一直向右走,向右既能最小化游戏目标,又能最大化?不合理,也就是说这种情况已经在不断的取 取 的过程中非法了。
那么得出结论,。感性理解一下结论,即连续两次移动先手和后手一定会选择不同的方向,最终走出一条折线。这具有优雅的正确性,因为一个方向更大化,另一个方向就是更小化。
所以对于一般的情况我们简化为了 。再预处理一下可以一轮进洞的情况就可将 放在斜率为 的独立的斜线上进行。由于洞的数量非常少,我们仅需要知道哪里的 改变了,连续一段贡献相同。
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
信息
- ID
- 10078
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者