C、答题卡

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

牛牛即将要参加考试,他学会了填答题卡。

可惜他竖着的答题卡填成了横着的 : (

好奇的他想知道对于 n 道题,每道题 n 个选项的答题卡 ( n * n 的矩阵 ),满足横答题卡和竖答题卡图形一致的方案数有多少种。

注:每道题只能选择一个选项,即 n * n 的矩阵中只能涂黑 n 个空。求横竖对称的方案数。


输入描述:

第一行给出 n。

输出描述:

输出方案数,答案对  取模
示例1

输入

复制
3

输出

复制
4

说明

备注:

对于  的数据有 

对于 的数据有

解题思路

比较明显的规律或者动态规划的题目,先从小开始慢慢推一下吧。
找到前4项是 1,2,4,10。你会发现第四项有点规律了。但是没有关系,我们有一个神奇的网站OEIS跳转里面第一个。
找到递推关系式:图片说明

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
    ll s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}


const int N = 1e5+7;
const int MOD = 1e9+7;
ll dp[N]={1, 1, 2, 4, 10, 26, 76, 232, 764, 2620, 9496, 35696, 140152, 568504, 2390480, 10349536};

int main(){
    int n=read();
    for(int i=15;i<=n;++i)
        dp[i]=(dp[i-1]+(i-1)*dp[i-2])%MOD;
    printf("%lld\n",dp[n]);
    return 0;
}

那么竟然有这个递推式子,我们返过去看看怎么推出它来。
给定一个n阶方阵,我们想第一行如果放在第一列上剩下的就是(n - 1) * (n - 1)的题目所求方案数,如果第一行不放在第一列一共有(n - 1)种方法,比如说返在第二列,那么对应第二行就唯一确定了只能放在第一列,除开这俩行,剩下(n - 2) * (n - 2)的题目所求方案数。
综上所述:dp[1] = 1; dp[2]=2
dp[i] = dp[i-1] + (i-1) * dp[i-2] (i>=3)
也是得到了我们的递推式。