题解:CF2097B Baggage Claim
题目传送门:洛谷 || CF
神秘分类讨论题。赛时两罚才过。/kk
蒟蒻的做法可能更为麻烦一些。
题目大意
一条路径是合法的,当且仅当每次只能走到相邻格子,且一个格子不能经过两次。现在有一条长为奇数的路径,不告诉你其中第偶数个格子,问有多少种合法填法。
题目分析
首先有几种情况可以特判掉,方便后续处理:
-
存在
i 使得|x_{i+1}-x_i|+|y_{i+1}-y_i| \neq 2 ; -
存在
i,j 满足|x_{i+1}-x_i|=2,|y_{j+1}-y_j|=2 使得\frac{x_{i+1}+x_i}{2}=x_j,\frac{y_{j+1}+y_j}{2}=y_i 。
发现可能有多个填法的只有一种情况:
但先等等。有的点其实是不能被选的。当
对图中的每个联通块都数出其中点数
-
a<c -
-
a=c -
-
最后把每个联通块的答案乘起来就行了。
AC Code
// by wangyizhi(571247)
#include<bits/stdc++.h>
//#include<bits/extc++.h>
using namespace std;
using ll=long long;
using ld=long double;
//#define int ll
using pii=pair<int,int>;
//bool Mst;
const int N=1e6+5,mod=1e9+7;
vector<int> g[N];
int x[N],y[N],to[N],used[N];
array<int,3> dfs(int u,int fa)
{
to[u]=1;
array<int,3> ans={1,used[u],(int)g[u].size()};
for(int v:g[u]) if(v!=fa&&!to[v])
{
auto res=dfs(v,u);
ans[0]+=res[0],ans[1]+=res[1],ans[2]+=res[2];
}
return ans;
}
//bool Med;
signed main()
{
// cerr<<"Memory Size: "<<abs((&Med)-(&Mst))/1024.0/1024<<" MB\n";
ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--) [&]()
{
int n,m,k,cnt=0,ans=1;
cin>>n>>m>>k;k++;
vector<vector<int>> num(n+2,vector<int>(m+2));
for(int i=1;i<=n*m;i++) g[i].clear(),to[i]=0,used[i]=0;
for(int i=1;i<=k;i++) cin>>x[i]>>y[i];
for(int i=1;i<k;i++)
if(abs(x[i]-x[i+1])+abs(y[i]-y[i+1])!=2)
{
cout<<0<<"\n";
return;
}
for(int i=1;i<k;i++)
{
if(x[i]==x[i+1]||y[i]==y[i+1])
{
int xx=(x[i]+x[i+1])/2,yy=(y[i]+y[i+1])/2;
if(!num[xx][yy]) num[xx][yy]=++cnt;
if(used[num[xx][yy]])
{
cout<<0<<"\n";
return;
}
used[num[xx][yy]]=1;
}
}
for(int i=1;i<k;i++)
{
if(abs(x[i]-x[i+1])==1)
{
if(!num[x[i]][y[i+1]]) num[x[i]][y[i+1]]=++cnt;
if(!num[x[i+1]][y[i]]) num[x[i+1]][y[i]]=++cnt;
g[num[x[i]][y[i+1]]].push_back(num[x[i+1]][y[i]]);
g[num[x[i+1]][y[i]]].push_back(num[x[i]][y[i+1]]);
}
}
for(int i=1;i<=cnt;i++) if(!to[i])
{
auto p=dfs(i,0);p[2]/=2;
if(p[2]<p[0])
{
if(!p[1]) ans=1ll*ans*p[0]%mod;
else if(p[1]>1)
{
cout<<0<<"\n";
return;
}
}
else if(p[2]==p[0])
{
if(!p[1]) ans=1ll*ans*2%mod;
else
{
cout<<0<<"\n";
return;
}
}
else
{
cout<<0<<"\n";
return;
}
}
cout<<ans<<"\n";
}();
return 0;
}