专栏文章
题解:CF1866I Imagination Castle
CF1866I题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @minvdk82
- 此快照首次捕获于
- 2025/12/02 08:58 3 个月前
- 此快照最后确认于
- 2025/12/02 08:58 3 个月前
做法
首先考虑暴力 DP,设 代表先手走完之后到了 时是先手必胜还是必败( 表示必胜, 表示必败)。显然有对于所有关键点,,且 。倒着 DP 即可。
考虑优化。发现 当且仅当 无法走到任何 的位置(否则下一轮轮到后手就可以直接走到一个必胜点)。于是可以发现一个重要性质:不考虑关键点,每行和每列最多有一个 。于是考虑设 表示第 行除了关键点的 在哪个位置, 表示第 列除了关键点的 在哪个位置( 表示没有)。发现只要知道了所有大于 的 的 ,就能算出 。于是 与 是独立的,分别倒着计算即可。
具体地, 需要不能走到它下面的 ,设 为所有大于 的行的 所在的列的 MEX。如果 大于这一行所有关键点所在列的最大值,那么 ,否则 。用 set 维护即可。
代码
CPP#include<bits/stdc++.h>
#define int long long
#define ll long long
#define ull unsigned long long
#define pii pair<ll,ll>
#define fi first
#define se second
#define i128 __int128
#define ALL(x) x.begin(),x.end()
#define popcount(x) __builtin_popcountll(x)
#ifdef LOCAL
#include "debug.h"
#else
#define debug(...) 42
#endif
using namespace std;
const int INF=1e18;
const int N=200005;
const int MOD1=1e9+7,MOD2=998244353;
const int MOD=MOD1;
int n,m,k;
int f[N],g[N];//这一行/列除了关键点的1
vector<int> vec1[N],vec2[N];
set<int> s;
void calc(int x){
//计算行
int t=(!s.empty()?*s.rbegin():-1);
int mx=0;
for(auto i:vec1[x]){
mx=max(mx,i);
}
//debug(x,mx,t);
if(t>mx)f[x]=t;
for(auto i:vec1[x]){
s.erase(i);
}
if(f[x]!=-1){
s.erase(f[x]);
}
if(x!=1)calc(x-1);
}
void calc2(int x){
int t=(!s.empty()?*s.rbegin():-1);
int mx=0;
for(auto i:vec2[x]){
mx=max(mx,i);
}
if(t>mx)g[x]=t;
for(auto i:vec2[x]){
s.erase(i);
}
if(g[x]!=-1){
s.erase(g[x]);
}
if(x!=1)calc2(x-1);
}
void solve_(){
cin>>n>>m>>k;
bool flg=0;
bool flg2=0;
for(int i=1;i<=k;i++){
int x,y;
cin>>x>>y;
if(x==1||y==1){
flg=1;
}
if(x==n&&y==m){
flg2=1;
}
vec1[x].push_back(y);
vec2[y].push_back(x);
}
if(!flg2){
vec1[n].push_back(m);
vec2[m].push_back(n);
}
if(n==1&&m==1){
cout<<"Bhinneka\n";
return;
}
if(n==1||m==1){
cout<<"Chaneka\n";
return;
}
if(flg==1){
cout<<"Chaneka\n";
return;
}
for(int i=1;i<=n;i++){
f[i]=-1;
}
for(int i=1;i<=m;i++){
g[i]=-1;
}
for(int i=1;i<=m;i++){
s.insert(i);
}
calc(n);
s.clear();
for(int i=1;i<=n;i++){
s.insert(i);
}
calc2(m);
for(int i=2;i<=n;i++){
if(f[i]==1){
cout<<"Chaneka\n";
return;
}
}
for(int i=2;i<=m;i++){
if(g[i]==1){
cout<<"Chaneka\n";
return;
}
}
cout<<"Bhinneka\n";
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int testcase,multitest=0;
if(multitest)cin>>testcase;
else testcase=1;
while(testcase--){
solve_();
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...