#include using namespace std; const int mod = 1e9 + 7; //取模 const int N = 1010; const int M = 1010; int n; //原序列长度 int m; //目标序列长度 int f[N][M]; int a[N]; // 原题链接 https://www.luogu.com.cn/problem/solution/UVA12983 int main() { //加快读入 cin.tie(0), ios::sync_with_stdio(false); //文件输入 freopen("UVA12983.in", "r", stdin); //文件输出 // freopen("UVA12983.out", "w", stdout); int T; //测试数据组数 cin >> T; for (int Case = 1; Case <= T; Case++) { // while(T--) ,由于要输出 Case +数字,所以写成for,为了怕占用i,j变量,起名为idx cin >> n >> m; //由n个数字中挑选,最终严格上升子序列的个数为m 个 int sum = 0; //结果为累加和,因为最终长度为m,可以从m,m+1,m+2,...,n个数字中选择,最终长度为m即可 // DP初始化 memset(f, 0, sizeof(f)); // f[i][j]表示 在前i个数字中选择,并且,是后一位是i的,并且长度是j的 子序列 个数 //个数的初始值 //这个初始值有意思:不管给我几个数字,最终生成的是位的子序列,那么,只有一种可能 for (int i = 1; i <= n; i++) f[i][1] = 1; for (int i = 1; i <= n; i++) cin >> a[i]; //读入原序列 //开始O(N^3)级的DP //小的数量在外层循环,大的数量在内层循环,这会影响很大的运算速率 for (int j = 2; j <= m; j++) // 小数在外层循环;j=1的已经根据实际意义给上了初始值1,从2开始递推 for (int i = j; i <= n; i++) // 大数在内层循环 for (int k = 1; k < i; k++) // 遍历所有前序可能 if (a[k] < a[i]) // 保证严格递增 f[i][j] = (f[k][j - 1] + f[i][j]) % mod; // 不断累加,不断取模 for (int i = m; i <= n; i++) sum += f[i][m]; //在m确定的情况下,每个一个m~n之间的原始长度都包含解 cout << "Case #" << Case << ": " << sum << endl; } return 0; }