题解:P12215 [蓝桥杯 2023 国 Python B] 困局
Circle_Table · · 题解
这边是题目传送门喵!
欢迎来博客园阅读喵!
这篇是首篇题解吗?
前言:
你们觉得
0<k<\min(n,8) 还是人类的语言吗?
题意
其实题目本身也挺清楚的,不过要注意的点是:既然每一个传送门都只能被使用一次,那么每个传送门都被使用就是恰好
思路
考虑样例,发现如果两个传送门之间有空地,那么这一块空地应该是对行走路线毫无影响的:一定会走过去而在这个过程中不发生传送。我知道这是一句废话,但是这启示我们直接将空地给拿掉,也就是先从
只要我能解决这个问题,然后就只用给这
你们觉得
0<k<\min(n,8) 还是人类的语言吗?
那我岂不是直接对每一个
实际上,鉴于数据范围这么小,可以直接搜索。
至于搜索的过程,我们用一个函数模拟行走的过程,把传送门作为一条边,然后每次把不同的建边的方案丢进去跑就可以了。具体模拟的方法还是看代码吧。
当然,打表也是完全可以的。
代码
#include <bits/stdc++.h>
#define loop(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define rloop(i,a,b) for(int i=(a);i>=(int)(b);i--)
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e6+5;
const ll mod=998244353;
int n,k;
ll cnt[15],ans;
int a[15];
bool vis[15];
int qmi(int a,int k){
int res=1;
while(k){
if(k&1)res=1ll*res*a%mod;
a=1ll*a*a%mod;
k>>=1;
}
return res;
}
ll calc(int n,int m){ // 组合数计算
if(m<0||m>n)return 0;
m=min(m,n-m);
ll x=1,y=1;
loop(i,1,m){
x=1ll*x*(n-i+1)%mod;
y=1ll*y*i%mod;
}
return 1ll*x*qmi(y,mod-2)%mod; // x/y
}
bool check(int k){ // 模拟
int t=2*k;
memset(vis,0,sizeof(vis));
int x=0,cnt=0;
while(++x<=t){
if(a[x]&&!vis[x]){
vis[x]=1;
x=a[x];
cnt++;
}
}
return cnt>=2*k; // cnt==2*k
}
void dfs(int u,int k){
int t=2*k;
while(u<=t&&a[u])u++;
if(u>t){
if(check(k))ans++;
return;
}
loop(v,u+1,t){
if(!a[v]){
a[u]=v;a[v]=u; // 建边
dfs(u+1,k);
a[u]=a[v]=0; // 断边
}
}
}
void init(){
cnt[0]=1;
loop(k,1,7){
memset(a,0,sizeof(a));
ans=0;
dfs(1,k);
cnt[k]=ans;
}
// loop(k,1,7)cout<<cnt[k]<<' ';
// cout<<'\n';
// 这一段其实输出的就是打表的结果。
return;
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);
init();
cin>>n>>k;
if(2*k>n)cout<<"0\n";
else cout<<1ll*calc(n,2*k)*cnt[k]%mod<<"\n";
return 0;
}
完结撒花!