HDU5288 OO’s Sequence 二分

6 篇文章 0 订阅

开始刷2015多校对抗赛的第一题

题目要求所有子序列中没有其约数的个数

显然需要nlogn的算法,对于一个数,我们需要求出最大的子序列,保证这段序列中没有其约数,然后利用乘法原理求解

所以就很容易想到用a,b数组分别记录s[i]左右最近的约数的位置

下面考虑求出a,b数组

首先约数是没有任何办法的,必须用根号n的代价枚举,然后只需要预先记录下每个数字出现的位置,然后利用位置下标的递增性二分求解

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define maxn 100009
#define mod 1000000007
#define rep(i, j, k) for(int i = j; i <= k; i++)

using namespace std;

int n, a[maxn], l[maxn], r[maxn];
long long ans = 0;
vector <int> s[maxn];

int main()
{
	while (scanf ("%d", &n) == 1)
	{
		ans = 0;
		rep (i, 1, n)
			s[i].clear ();
		rep (i, 1, n)
			scanf ("%d", &a[i]), s[a[i]].push_back (i);
		rep (i, 1, n)
		{
			l[i] = 0, r[i] = n + 1;
			for (int j = 1; j * j <= a[i]; j++)
				if (a[i] % j == 0)
				{
					int la, ra;
					if (s[j].size () > 0)
					{
						la = lower_bound (s[j].begin (), s[j].end (), i) - s[j].begin ();
						if (la - 1 >= 0)
							l[i] = max (l[i], s[j][la - 1]);
						ra = upper_bound (s[j].begin (), s[j].end (), i) - s[j].begin ();
						if (ra < s[j].size ())
							r[i] = min (r[i], s[j][ra]);
					}

					int next = a[i] / j;
					if (s[next].size () == 0)
						continue;
					la = lower_bound (s[next].begin (), s[next].end (), i) - s[next].begin ();
					if (la - 1 >= 0)
						l[i] = max (l[i], s[next][la - 1]);
					ra = upper_bound (s[next].begin (), s[next].end (), i) - s[next].begin ();
					if (ra < s[next].size ())
						r[i] = min (r[i], s[next][ra]);
				}
			if (r[i] > i && i > l[i])
				ans = (ans + (r[i] - i) * (i - l[i]) % mod) % mod;
		}
		cout << ans << endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值