您的位置:首页 > 产品设计 > UI/UE

HDU5288 OO’s Sequence 二分

2016-03-23 23:13 411 查看
开始刷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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: