2018/7/16 OO’s Sequence 训练日记2

Problem Description

OO has got a array A of size n ,defined a function f(l,r) represent the number of i (l<=i<=r) , that there's no j(l<=j<=r,j<>i) satisfy ai mod aj=0,now OO want to know

Input

There are multiple test cases. Please process till EOF.
In each test case: 
First line: an integer n(n<=10^5) indicating the size of array
Second line:contain n numbers ai(0<ai<=10000)

Output

For each tests: ouput a line contain a number ans.

Sample Input

5 1 2 3 4 5

Sample Output

23

题目大意:

给你一个数组A 定义 f(l , r)   表示 对于 i (l=<i<=r) 不存在 j (l<=j<=r &&j!=i) 使得 A[i]%A[j]==0的i的个数

 求所有l,r (1<=l<=n && 1<=r<=n l<=r)的f(l,r)的和

解题思路:

例如样例:1 2 3 4 5

当i=1时,1是1的因数,2不是1的因数,3不是1的因数,4不是1的因数,5不是1的因数,虽然1是1的因数,但是j!=i,因此,在区间(1,1),(1,2),(1,3),(1,4),(1,5)上,i=1都是一个解。

当i=2时,1是2的因数,2是2的因数,3不是2的因数,4不是2的因数,5不是2的因数,虽然2是2的因数,但是j!=i,因此,在区间(2,2),(2,3),(2,4),(2,5)上,i=2都是一个解。

当i=3时,1是3的因数,2不是3的因数,3是3的因数,4不是3的因数,5不是3的因数,虽然3是3的因数,但是j!=i,因此,在区间(2,3),(2,4),(2,5),(3,3),(3,4),(3,5)上,i=3都是一个解。

当i=4时,1是4的因数,2是4的因数,3不是4的因数,4是4的因数,5不是4的因数,虽然4是4的因数,但是j!=i,因此,在区间(3,4),(3,5),(4,4),(4,5)上,i=4都是一个解。

当i=5时,1是5的因数,2不是5的因数,3不是5的因数,4不是5的因数,5是5的因数,虽然5是5的因数,但是j!=i,因此,在区间(2,5),(3,5),(4,5),(5,5)上,i=5都是一个解。                                                                                         

我们会发现,当i是解时,则包含i的区间最大为i左边离它最近的因子的位置left[i]到i右边离它最近的因子的位置righ[i]。那么这个区间所包含的区间并且包含i的区间都是符合题目的。一共有(i-lef[i])*(righ[i]-i)个。把所有的i相加即可。

重点来了,如何寻找left[i]和righ[i],如果每一次都是遍历一遍数组,显然会T的。

因为题目给出的ai的取值范围是(0<ai<=10000),所有预处理出10000以内的每一个数在10000以内的因子。然后标记每一个i的左边和右边离它最近的它的因子的位置。

#include<bits/stdc++.h> 
using namespace std;
#define mod 1000000007
const int maxn = 1e5+100;
int l[maxn],r[maxn],a[maxn],pos[maxn];
vector<int>G[10005];
int main()
{
    for(int i=1;i<=10000;i++)
    {
        for(int j=i;j<=10000;j+=i)
        {
 
            G[j].push_back(i);
        }
    }
    int n;
    while(~scanf("%d",&n))
    {
        memset(pos,0,sizeof(pos));
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),l[i]=1,r[i]=n;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<G[a[i]].size();j++)
            {
                int v = G[a[i]][j];
                l[i] = max(l[i],pos[v]+1);
            }
            pos[a[i]] = i;
        }
        memset(pos,0,sizeof(pos));
        for(int i=n;i>=1;i--)
        {
            for(int j=0;j<G[a[i]].size();j++)
            {
                int v = G[a[i]][j];
                if(!pos[v])continue;
                r[i] = min(r[i],pos[v]-1);
            }
            pos[a[i]] = i;
        }
        long long ans = 0;
        for(int i=1;i<=n;i++)
        {
            ans+=(long long)(i-l[i]+1)*(r[i]-i+1);
            ans%=mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值