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;
}

不会有人直接交这个程序吧。。。。

这个是打表用的(坑一下直接抄题解的人)

posted @ 2021-12-05 09:50  huayucaiji  阅读(47)  评论(0编辑  收藏  举报