赤壁之战

给定一个长度为N的序列A,求A有多少个长度为M的严格递增子序列。

输入格式
第一行包含整数T,表示共有T组测试数据。

每组数据,第一行包含两个整数N和M。

第二行包含N个整数,表示完整的序列A。

输出格式
每组数据输出一个结果,每个结果占一行。

输出格式为“Case #x: y”,x为数据组别序号,从1开始,y为结果。

由于数据可能很大,请你输入对10^9+7取模后的结果。

数据范围
1≤T≤100,
1≤M≤N≤1000,
∑Ti=1Ni×Mi≤10^7
序列中的整数的绝对值不超过10^9。

输入样例:
2
3 2
1 2 3
3 2
3 2 1
输出样例:
Case #1: 3
Case #2: 0

TLE代码,实际上只是优化了寻找边界,减少第三层循环的大小,状态转移还是朴素的O(n^3)。

#include<bits/stdc++.h>

#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
const int N = 1e3 + 10, M = 1e3 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int T, n, m, cnt;
int a[N], f[N][M];
multiset<pii > heap;

inline void init() {
    memset(f, 0, sizeof(f));
    for (int i = 1; i <= n; i++)f[i][1] = 1;
    heap.clear(), heap.insert({INF, 0});
}

int main() {
    cin >> T;
    while (T--) {
        scanf("%d%d", &n, &m), init();
        for (int i = n; i >= 1; i--)scanf("%d", &a[i]);
        for (int i = 1; i <= n; i++) {
            auto t = heap.upper_bound({a[i], 0});
            while ((*t).fi != INF) {
                for (int j = 2; j <= m; j++)
                    f[i][j] = (f[i][j] + f[(*t).se][j - 1]) % MOD;
                t++;
            }
            heap.insert({a[i], i});
        }
        int ans = 0;
        for (int i = m; i <= n; i++)ans += f[i][m];
        printf("Case #%d: %d\n", ++cnt, ans);
    }
    return 0;
}

利用树状数组可以将第三层循环降到O(logn),最终总的时间复杂度为O(NMlogN)

#include <bits/stdc++.h>

#define lowbit(x) ((x)&(-(x)))
using namespace std;
const int N = 1e3 + 10, MOD = 1e9 + 7;
int T, n, m, cnt;
int a[N], b[N], c[N];
int f[N][N], tot;
unordered_map<int, int> num;

inline int ask(int x) {
    int res = 0;
    for (; x; x -= lowbit(x))res = (res + c[x]) % MOD;
    return res;
}

inline void add(int x, int y) {
    for (; x <= n; x += lowbit(x))c[x] = (c[x] + y) % MOD;
}

int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)scanf("%d", &a[i]);
        memcpy(b, a, sizeof(a));
        sort(b + 1, b + 1 + n);
        tot = unique(b + 1, b + 1 + n) - (b + 1);
        for (int i = 1; i <= tot; i++)num[b[i]] = i;
        for (int i = 1; i <= n; i++)a[i] = num[a[i]];
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= n; i++)f[i][1] = 1;
        for (int j = 2; j <= m; j++) {
            memset(c, 0, sizeof(c));
            for (int i = 1; i <= n; i++) {
                f[i][j] = (f[i][j] + ask(a[i] - 1)) % MOD;
                add(a[i], f[i][j - 1]);
            }
        }
        int ans = 0;
        for (int i = m; i <= n; i++)ans = (ans + f[i][m]) % MOD;
        printf("Case #%d: %d\n", ++cnt, ans);
    }
    return 0;
}
发布了329 篇原创文章 · 获赞 28 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45323960/article/details/104936075