赛后当天学长就说了树状数组,结果在一个星期后赖床时才有了一点点思路……
因为无法提交,不确定是否正确。。嗯。。有错希望指出,谢谢。。。
嗯。。已经A了。。提交地址http://acm.uestc.edu.cn/#/problem/show/1217
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; /** 题意:T代表测试组数 (T<=100) 每组两个数N, M(1<=N<=1000,1<=M<=N) 给N个数ai(1<=ai<=10^9) 求该数列的m长递增子序列 方法:容易想到dp[i][k]表示到第i个数,长度为k的子序列,O(N^3)可解 通过树状数组可以优化到O(N^2lgN) */ struct node{ int data; int pos; bool operator < (const node a) const { if (data == a.data) return pos < a.pos; return data < a.data; } } a[1005]; int c[1005][1005]; // c[k][i] 结尾数字为i,长度为k的子序列数量 int b[1005]; int N, M; const int MOD = 1000000007; int lowbit(int x) { return x & (-x); } int sum(int x, int n) { int ans = 0; while (n > 0) { ans = (ans + c[x][n]) % MOD; n -= lowbit(n); } return ans; } void plu(int x, int pos, int num) { while (pos <= N) { c[x][pos] = (c[x][pos] + num) % MOD; pos += lowbit(pos); } } int main() { int t, cas = 0; scanf("%d", &t); while (t--) { scanf("%d%d", &N, &M); for (int i = 1; i <= N; ++i) { scanf("%d", &a[i].data); a[i].pos = i; } // 离散化 sort(a + 1, a + N + 1); int cnt = 1; b[a[1].pos] = cnt; for (int i = 2; i <= N; ++i) { if (a[i].data > a[i - 1].data) cnt++; b[a[i].pos] = cnt; } //for (int i = 1; i <= N; ++i) cout << b[i] << endl; memset(c, 0, sizeof c); for (int i = 1; i <= N; ++i) { plu(1, b[i], 1); // 以每个数结尾的长度为1的数都是1 for (int k = 2; k <= M; ++k) { int temp = sum(k - 1, b[i] - 1); // 所有比b[i]小的数长度为k-1的和就是以b[i]为结尾的长度为k的了。。 plu(k, b[i], temp); } } int ans = sum(M, N); printf("Case #%d: %d ", ++cas, ans); } return 0; } /** Input: 5 3 2 1 2 3 3 2 3 2 1 3 1 1 2 3 3 2 1 1 2 7 3 1 1 2 2 1 1 4 Output: 3 0 3 2 4 */