hdu 5288 OO's sequence【因子分解】

来源:互联网 发布:边伯贤直播软件 编辑:程序博客网 时间:2024/06/03 16:55

题目大意:
给定长度为n(n<=105)的整数序列(a<=104),求出所有子区间中不被区间内其他数整除的数的个数和,结果取余109+7;

思路:
一个个枚举区间肯定行不通,可以根据每个整数对结果的贡献求和;
对于第i个数ai,找出ai左右第一个被整除的边界l、r,则ai的贡献为(i-l)*(r-i);
利用标记数组可以在sqrt(a)内找出左右边界,因此总复杂度为O(n*sqrt(a))。

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int mod = 1e9+7;const int MAXN = 1e5+10;int a[MAXN], l[MAXN], r[MAXN];int vis[MAXN];int main(int argc, char const *argv[]){    int n;    while(~scanf("%d", &n))        {        for(int i = 1; i <= n; i++)            scanf("%d", &a[i]);        memset(vis, 0, sizeof(vis));        for(int i = 1; i <= n; i++)        {            l[i] = 0;            for(int j = 1; j * j <= a[i]; j++)            {                if(a[i] % j)                    continue;                if(vis[j])                    l[i] = max(l[i], vis[j]);                if(vis[a[i]/j])                    l[i] = max(l[i], vis[a[i]/j]);            }            vis[a[i]] = i;        }        memset(vis, 0, sizeof(vis));        for(int i = n; i >= 1; i--)        {            r[i] = n + 1;            for(int j = 1; j * j <= a[i]; j++)            {                if(a[i] % j)                    continue;                if(vis[j])                    r[i] = min(r[i], vis[j]);                if(vis[a[i]/j])                    r[i] = min(r[i], vis[a[i]/j]);            }            vis[a[i]] = i;        }        long long ans = 0;        for(int i = 1; i <= n; i++)        {            ans += (i - l[i]) * (r[i] - i);            ans %= mod;        }        printf("%I64d\n", ans);    }    return 0;}
0 0
原创粉丝点击