开始刷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;
}