题解:CF2097B Baggage Claim
首先如果两个相邻的点的曼哈顿距离不为
对于相邻的两个奇数点,如果他们是一条水平或者垂直的线,那么他们的中点一定要选,那么我们用
由于每个点只能选择一次,那么我们将问题转换为对我们新建的图给无向边定向,使得每个点的入度最大为
由于
对于其他连通块(假设有
- 如果是一棵树,那么我们可以选择一个定点使其没有入边,这样就有
n 中选择。 - 如果给定的是一颗基环树,可以知道只有环上正向和反向两种选择,故对答案的贡献是
2 。 - 对于其他情况的答案就是
0 (因为边数已经大于点数了,无论如何都有点的入度大于1 )。
对于不同连通块我们直接相乘即可。这样的复杂度是
Code
#include <bits/stdc++.h>
#define pii pair<int,int>
#define pb emplace_back
#define ll long long
#define mk make_pair
#define se second
#define fi first
//#define mid ((l+r)>>1)
//#define rs now<<1|1
//#define ls now<<1
using namespace std;
bool Mst;
const int Max=2e6+10;
const int mod=998244353;
const int inf=1e9+10;
inline int read(){
int res=0,v=1;
char c=getchar();
while(c<'0'||c>'9'){v=(c=='-'?-1:1);c=getchar();}
while(c>='0'&&c<='9'){res=(res<<3)+(res<<1)+(c^48);c=getchar();}
return res*v;
}
template <int mod>
struct modint{
int val;
static int norm(const int &x){return x<0?x+mod:x;}
static int Norm(const int &x){return x>=mod?x%mod:x;}
modint inv()const{
int a=val,b=mod,u=1,v=0,t;
while(b>0)t=a/b,swap(a-=t*b,b),swap(u-=t*v,v);
return modint(u);
}
modint():val(0){}
modint(const int &m):val(norm(m)){}
modint(const long long &m):val(norm(m%mod)){}
modint operator -()const{return modint(norm(-val));}
bool operator ==(const modint &x){return val==x.val;}
bool operator !=(const modint &x){return val!=x.val;}
bool operator <=(const modint &x){return val<=x.val;}
bool operator >=(const modint &x){return val>=x.val;}
bool operator >(const modint &x){return val>x.val;}
bool operator <(const modint &x){return val<x.val;}
modint& operator *=(const modint &x){return val=static_cast<int>(1ll*val*x.val%mod),*this;}
modint& operator <<=(const modint &x){return val=(1ll*val<<x.val)%mod,*this;}
modint& operator +=(const modint &x){return val=Norm(1ll*val+x.val),*this;}
modint& operator -=(const modint &x){return val=norm(1ll*val-x.val),*this;}
modint& operator >>=(const modint &x){return val>>=x.val,*this;}
modint& operator ^=(const modint &x){return val^=x.val,*this;}
modint operator >>(const modint &x){return modint(*this)>>=x;}
modint operator <<(const modint &x){return modint(*this)<<=x;}
modint& operator /=(const modint &x){return *this*=x.inv();}
modint operator +(const modint &x){return modint(*this)+=x;}
modint operator -(const modint &x){return modint(*this)-=x;}
modint operator *(const modint &x){return modint(*this)*=x;}
modint operator /(const modint &x){return modint(*this)/=x;}
modint operator ^(const modint &x){return modint(*this)^=x;}
friend std::ostream& operator<<(std::ostream& os,const modint &a){return os<<a.val;}
friend std::istream& operator>>(std::istream& is,modint &a){return is>>a.val;}
};
typedef modint<1000000007>m17;
vector<int>v[Max];
int id[1010][1010];
void add(int x,int y){v[x].pb(y);v[y].pb(x);}
pii p[Max];
int vis[1010*1010];
int fa[Max];
int FindFa(int x){return x==fa[x]?x:fa[x]=FindFa(fa[x]);}
void merge(int x,int y){
x=FindFa(x);y=FindFa(y);
fa[x]=y;
}
int siz[Max],num[Max];
void dfs(int now){
vis[now]=1;siz[now]=1;num[now]=v[now].size();
for(auto to:v[now]){
if(vis[to])continue;
dfs(to);num[now]+=num[to];siz[now]+=siz[to];
}
}
void work(){
int n=read(),m=read(),k=read();int cnt=0;
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)id[i][j]=++cnt;
for(int i=0;i<=cnt;++i)v[i].clear(),vis[i]=siz[i]=num[i]=0;
int tag=0;
for(int i=1;i<=k+1;++i){
int x,y;x=read();y=read();
p[i]=mk(x,y);
if(i!=1){
if(abs(x-p[i-1].fi)+abs(y-p[i-1].se)!=2){
tag=1;
}
if(abs(x-p[i-1].fi)==abs(y-p[i-1].se)){
add(id[x][p[i-1].se],id[p[i-1].fi][y]);
}else{
add(0,id[(x+p[i-1].fi)/2][(y+p[i-1].se)/2]);
}
}
}
if(tag){
cout << "0\n";
return ;
}
for(int i=0;i<=cnt;++i)fa[i]=i;
for(int i=0;i<=cnt;++i){
for(auto to:v[i]){
merge(i,to);
}
}
m17 ans=1;
for(int i=1;i<=cnt;++i){
if(FindFa(i)!=FindFa(0)&&!vis[i]){
dfs(i);
if(num[i]==siz[i]*2)ans*=2;
else if(num[i]==(siz[i]-1)*2)ans*=siz[i];
else ans=0;
}
}
dfs(0);
if(num[0]!=(siz[0]-1)*2)ans=0;
cout << ans << "\n";
}
bool Med;
signed main(){
int T=read();
while(T--)work();
cerr<< "Time: "<<clock()/1000.0 << "s\n";
cerr<< "Memory: " << (&Mst-&Med)/1000000.0 << "MB\n";
return 0;
}
/*
*/