您的位置:首页 > 其它

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

2016-05-09 15:32 357 查看
题意:给定一个数组,求严格递增子序列的个数

思路:根据经典的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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息