fzu oj 2236 第十四个目标 树状数组好题 dp

来源:互联网 发布:framework7用什么js 编辑:程序博客网 时间:2024/05/28 05:15

题意:给定一个数组,求严格递增子序列的个数


思路:根据经典的LIS问题,很快就可以设计出状态转移方程, dp[i] = sum( dp[j] ) + 1, (0<j<i && a[j]<a[i]), 但这是一个o(n^2)的复杂度,必然超时,那么可以用树状数组加速,因为数组开不下,要离散化

对于树状数组理解可参考http://blog.csdn.net/wyt734933289/article/details/45892281,和这题思路相似


题目链接:http://acm.fzu.edu.cn/problem.php?pid=2236


#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn = 100005;const int mod = 1000000007;int n, cnt;int a[maxn], b[maxn], c[maxn], dp[maxn];int bin_search(int num){    int l = 0, r = cnt - 1, m;    while(l <= r)    {        m = (l+r) >> 1;        if(b[m] > num) r = m - 1;        else if(b[m] < num) l = m + 1;        else return m;    }    return -1;}int lowbit(int t){    return t & (-t);}int getsum(int x){    int ans = 0;    while(x > 0)    {        ans = (ans + c[x]) % mod;        x -= lowbit(x);    }    return ans;}void update(int x, int val){    while(x <= cnt)    {        c[x] = (c[x] + val) % mod;        x += lowbit(x);    }}int main(){    while(~scanf("%d", &n))    {        for(int i = 0; i < n; i++)        {            scanf("%d", &a[i]);            b[i] = a[i];        }        cnt = 1;        sort(b, b+n);        for(int i = 1; i < n; i++)            if(b[i] != b[i-1])                b[cnt++] = b[i];        memset(c, 0, sizeof(c));        memset(dp, 0, sizeof(dp));        int ans = 0;        for(int i = 0; i < n; i++)        {            int pos = bin_search(a[i]);            dp[i] = (getsum(pos) + 1) % mod;//因为树状数组从1开始,所以这里的pos相当于pos-1            ans = (ans + dp[i]) % mod;            update(pos + 1, dp[i]);        }        printf("%d\n", ans);    }    return 0;}


0 0
原创粉丝点击