【题目】
题目描述:
有 n 个不同的数列成一个队列,现在可以若干次选择两个数交换位置,每个数只能被交换一次。现在 L 想知道能得到多少种不同的队列。
输入格式:
第一行是一个整数 T,表示有 T 组数据
接下来 T 行,每一行是一个整数 N 表示数量
输出格式:
输出 T 行,每行一个正整数表示这组数据的答案(模 1e9+7 的值)
样例数据:
输入
2
2
3输出
2
4
备注:
数据规模与约定:
20% 的数据,N ≤ 10
40% 的数据,N ≤ 1000
60% 的数据,N ≤ 50000
100% 的数据,1 ≤ N ≤ 1000000,1 ≤ T ≤ 100000
数据中均匀分布着 50% 的数据满足T ≤ 5
【分析】
首先看到题面,再看到数据范围,嗯,这是一道递推的题没跑了
emmm……本蒟蒻不太喜欢递推的题因为一般我都要推很久或者根本推不出来
做递动规的时候,如果自己想不出递推式,就要用一些神奇的方法,比如说自己暴力找出小数据的值,对这些值找规律(本蒟蒻就经常这么搞),一般运气好的话还是很容易找到规律的
下面是正解的推导:
我们用 f [ i ] 表示有 i 个数时的方案数,那么最后的答案 answer = f [ n ]
推到 f [ i ] 时,有如下两种情况:
- 第 i 个数和前(i - 1)个数没有交换,f [ i ] 加上 f [ i - 1 ]
- 第 i 个数和前(i - 1)个数中的某一个交换了,f [ i ] 加上 (i - 1)* f [ i - 2 ]
所以最后的递推式就是 f [ i ] = f [ i - 1 ] + (i - 1)* f [ i - 2 ]
【代码】
递推式都出来了,AC 还会远吗~
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1000005;
const int mod=1e9+7;
long long f[N];
int main()
{
// freopen("queue.in","r",stdin);
// freopen("queue.out","w",stdout);
int n,i,x;
scanf("%d",&n);
f[1]=1;
f[2]=2;
for(i=3;i<=N;++i)
f[i]=(f[i-1]+(i-1)*f[i-2])%mod;
for(i=1;i<=n;++i)
{
scanf("%d",&x);
printf("%lld\n",f[x]);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}