Permutation

本题是今天哈理工的一个网络赛上的排列组合题。n个人排成一队,队头的人编号为1,后面的人编号分别为2,3,…,n. 1号人前面没有人,i号人的前面是i-1。 现在Kim想让这n个人重新排队,要求重新排队后编号为i的人前面不能是i-1。问有多少种排队的方法。方案数可能很大,输出答案模1e9+7。

当时做这道题的时候有点乱,光想着打表找规律了,再者是才复出一个月,思维远不如以前,结果就是用了好多时间到最后还是没做出来。网络赛结束后静下心来想了一会儿还是想出来了。如果这道题让高三时的我做,应该很快能AC。

说说思路:用f(n)表示有n个人时的排列方法,现在考虑n+1的情况,当把1排在最后一位时,前面的数字相对于1的位置是任意的,也就是说前面的2~n+1有f(n)种排列方法;当末尾的数字是2~n时,前面的排列方法也是f(n)种,具体为什么我也不知道该怎么表达,拿2在末尾来举例,因为前n个数里没有了1,2组合,1和3是可以互换位置的,这样下来排列方式就会多,但是注意,这个时候以1结尾的数列是不能接在2前面的,于是又要少几种排列,刚好抵消了;当末尾数字是n+1时,前面的排列方法有f(n)-(f(n-1)-(f(n-2)-...)),还是拿具体数字举例,当n=5时,5在末尾时,前面的排列方法应该是f(4)-(4在末尾时的排列方法),而(4在末尾时的排列方法)又等于f(3)-(3在末尾时的排列方法)......递推下去。

递推公式为:f(1)=0,f(2)=1,f(3)=f(2)+f(2)+f(2)-0,f(4)=f(3)+f(3)+f(3)+f(3)-(f(2)-0),f(5)=f(4)+f(4)+f(4)+f(4)+(f(4)-(f(3)-(f(2)-0)))......

因为比赛已经结束,所以不能评测了,贴一个没有MOD的代码,应该是对的吧。。。。。。

#include
#include
#include
#include
using namespace std;

const int MOD = 1000000007;
const int maxn = 1000000+10000;

int T;
int f[maxn];

void init()
{
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
}

void readdata()
{
	scanf("%d", &T);
}

void work()
{
	f[1] = 1; f[2] = 1;
	int cnt = 0;
	for(int i = 3; i <= 1000000; i++)
	{
		f[i] = f[i-1]*i - cnt;
		cnt = f[i-1]-cnt;
	}
	while(T--)
	{
		int n;
		scanf("%d", &n);
		printf("%d\n",f[n]);
	}
}

int main()
{
	init();
	readdata();
	work();
	return 0;
}

你可能感兴趣的:(Permutation)