2015 多校赛 第一场 1001 (hdu 5288)

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 a imod a j=0,now OO want to know [∑i=1n ∑j=i n f(i,j) ] mod (10^9+7)
 

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 a i(0<a i<=10000) 
 

Output

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

Sample Input

5 1 2 3 4 5
 

Sample Output

23
 
题意:给出长度为n的数列,设函数f(i,j)表示,在a[i]到a[j]中,其中i<=ti<=j,满足a[ti]%a[tj]!=0的ti的个数,其中tj为不等于ti的任意 i 到 j 中的数。
求出 [∑i=1n ∑j=i n f(i,j) ] mod (10^9+7)。
 
思路:对于数列中的每一个数,求出其被所有可行区间包含的次数。
 
代码与注释如下。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=10005,maxx=100005;
const long long mod=1000000007;
vector<int>divi[maxn];
int a[maxx],l[maxx],r[maxx],pos[maxn],n;
void ini(){
    for(int i=1;i<=10000;i++)
        for(int j=1;j<=i;j++)
            if(i%j==0) divi[i].push_back(j);
    //预处理出10000内所有数的因子
}
int main(){
    ini();
    while(~scanf("%d",&n)){
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        memset(l,-1,sizeof(l));
        memset(r,0x3f,sizeof(r));
        memset(pos,-1,sizeof(pos));
        //l[i]表示a[i]左边与之最接近的它的因子的下标
        for(int i=0;i<n;i++){
            int lef=-1;
            for(int j=0;j<divi[a[i]].size();j++)
                lef=max(lef,pos[divi[a[i]][j]]);
            pos[a[i]]=i;
            //pos数组用于更新维护最靠近a[i]的因子数的下标
            l[i]=lef;
        }
        memset(pos,0x3f,sizeof(pos));
        //r[i]表示a[i]右边与之最接近的它的因子的下标
        for(int i=n-1;i>=0;i--){
            int rig=0x3f3f3f3f;
            for(int j=0;j<divi[a[i]].size();j++)
                rig=min(rig,pos[divi[a[i]][j]]);
            pos[a[i]]=i;
            //pos数组用于更新维护最靠近a[i]的因子数的下标
            r[i]=rig;
        }
        long long ans=0,L,R;
        for(int i=0;i<n;i++){
            if(l[i]==-1) L=i+1;
            //若为原值,则说明a[i]左边不存在因子
            else L=i-l[i];
            //否则,令L为a[i]到其因子右边第一个数之间的个数
            if(r[i]==0x3f3f3f3f) R=n-i;
            else R=r[i]-i;
            ans=(L*R%mod+ans)%mod;
            //L*R为包含a[i]的连续区间的组合数。
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

 
posted @ 2015-07-21 18:54  轶辰  阅读(158)  评论(0编辑  收藏  举报