CF285D (打表+搜索)
CF285D
解题思路
这个题,我一看,哦,\(n\leq 16\),而且又是输入只有 \(n\)。果断打表啊!
关键在于如何快速打表。
我们可以先找出 \(C=(1,2,\cdots,n)\) 的方案数,然后再乘以 \(n!\) 就是总方案数了。我们如果爆搜的话就是 \(O(n*n!)\)。看起来好像跑的很慢 ,其实加上合理剪枝跑的速度还可以接受。
我们如果手玩一下 \(n\leq 5\) 的结果,或者让程序跑 \(n\leq 12\) 的答案(这部分跑的飞快),你就会发现 \(n\) 为偶数的时候,答案是 \(0\)。这样我们对于 \(n\) 为偶数的情况又可以不算了。
如果你像追求更高的效率,可以使用 Meet-in-the-middle。当然,不加这个优化也可以在 \(6\ min\) 内跑完,最后打表即可。
代码
//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
using namespace std;
int read() {
char ch=getchar();
int f=1,x=0;
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
const int MAXN=16,MOD=1e9+7;
int n;
int ans[MAXN],jc[MAXN];
bool vis[MAXN][2];
void dfs(int n,int x) {
if(x==n+1) {
ans[n]++;
return ;
}
for(int i=1;i<=n;i++) {
if(!vis[i][0]) {
int j=(x-1-i+2+n)%n;
if(!j) {
j=n;
}
if(!vis[j][1]) {
vis[i][0]=1;
vis[j][1]=1;
dfs(n,x+1);
vis[i][0]=0;
vis[j][1]=0;
}
}
}
}
int main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int t=16;
jc[0]=1;
for(int i=1;i<=t;i++) {
jc[i]=1ll*jc[i-1]*i%MOD;
if(i&1) {
dfs(i,1);
ans[i]=1ll*ans[i]*jc[i]%MOD;
}
else {
ans[i]=0;
}
printf("ans[%d]=%d;\n",i,ans[i]);
}
//fclose(stdin);
//fclose(stdout);
return 0;
}
不会有人直接交这个程序吧。。。。
这个是打表用的(坑一下直接抄题解的人)