HDU 3450 Counting Sequences 树状数组

本文探讨了一种解决类似HDU3030的问题策略,通过使用动态规划和树状数组进行优化。文章详细介绍了算法设计、代码实现及应用案例,旨在提升解决此类问题的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题和 HDU 3030 很像先写出 dp 方程, 是n ^ 2 dp 用树状数组优化

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;
const int MOD = 9901;
const int N = 100007;

int sum[N];
int tmp[N];
int num[N];
int dp[N];

int qcf(int n)
{
	sort(num + 1, num + 1 + n);
	int ans = 1;
	for(int i = 2; i <= n; i++)
		if(num[i] != num[i - 1])
			num[++ans] = num[i];
	return ans;
}

inline int lb(int x)
{
	return x & (-x);
}

int bf(int l, int r, int a)
{
	while(l <= r)
	{
		int m = (l + r) >> 1;
		if(num[m] == a)
			return m;
		if(num[m] > a)
			r = m - 1;
		else
			l = m + 1;
	}
	return -1;
}

void add(int x, int v, int n)
{
	while(x <= n)
	{
		sum[x] += v;
		if(sum[x] < 0) //由于有-法, 可能会变成负数, 没有这句就错了, 就是这里害我WA好久, 直接用取莫的可以忽略= =
			sum[x] += MOD;
		if(sum[x] >= MOD)
			sum[x] -= MOD;
		x += lb(x);
	}
}

int que(int x)
{
	int ans = 0;
	while(x > 0)
	{
		ans += sum[x];
		if(ans >= MOD)
			ans -= MOD;
		x -= lb(x);
	}
	return ans;
}

int bf2(int l, int r, int a, int d) //找符合条件的最右边的值
{
	int p = -1;
	while(l <= r)
	{
		int m = (l + r) >> 1;
		if(m == p)
			break;
		p = m;
		if(num[m] - a <= d)
			l = m;
		else
			r = m;
	}
	return l;
}

int bf3(int l, int r, int a, int d) //找符合条件的最左边的值
{
	int p = -1;
	while(l <= r)
	{
		int m = (l + r) >> 1;
		if(m == p)
			break;
		p = m;
		if(a - num[m] <= d)
			r = m;
		else
			l = m;
	}
	return r;
}

int main()
{
//	freopen("in.txt", "r", stdin);
	int n, d;
	while(~scanf("%d%d", &n ,&d))
	{
		for(int i = 1; i <= n; i++)
			scanf("%d", tmp + i), num[i] = tmp[i];
		int m = qcf(n);
		memset(sum, 0, sizeof(sum));
		dp[1] = 1;
		int x = bf(1, m + 1, tmp[1]);
		int y = bf2(x, m + 1, tmp[1], d);
		int z = bf3(1, x + 1, tmp[1], d);
		add(z, 1, m);
		add(y + 1, -1, m);
		for(int i = 2; i <= n; i++)
		{
			x = bf(1, m + 1, tmp[i]);
			y = bf2(x, m + 1, tmp[i], d);
			z = bf3(1, x + 1, tmp[i], d);
			dp[i] = 1 + que(x);
			if(dp[i] >= MOD)
				dp[i] -= MOD;
			add(z, dp[i], m);
			add(y + 1, -dp[i], m);
		}
		int ans = 0;
		for(int i = 1; i <= n; i++)
		{
			ans += dp[i] - 1;
			if(ans >= MOD)
				ans -= MOD;
		}
		printf("%d\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值