HDU5288 OO’s Sequence

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 a i mod a j=0,now OO want to know
i=1nj=inf(i,j) mod 109+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
 
Author
FZUACM
 
Source
 
一考思维,就想GG,搞了好长时间
这道题目的解法是: 通过预处理,记录 a[i] 的左右边界(所谓的左右边界时 在从 a[i] 当前位置往左往右找,找到左边第一个和右边第一个能够整除 a[i] 的数,这两个数就是a[i]的左右边界)然后记录到 l[] & r[] 中, 这样 a[i] 对 ans 的贡献是 (i - l[i]) * (r[i] - i);
在预处理 l[] 数组时,用pre[j]标记一下 j (表示 j 最后一次出现的位置),如果 j 在之前已经遇到过且右边界没有被更新过,就将 pre[j] 的边界更新到当前 i 所在的位置。
 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define LL long long
#define MAXN 100010
using namespace std;
const LL MOD = 1e9 + 7;
int a[MAXN];
LL l[MAXN], r[MAXN], pre[MAXN], last[MAXN];
int main() {
      int n;
      while(~scanf("%d", &n)) {
            for(int i = 1; i <= n; ++i) {
                  scanf("%d", a + i);
                  l[i] = 0, r[i] = n+1;
            }
            memset(pre, 0, sizeof(pre));
            memset(last, 0, sizeof(last));

            for(int i = 1; i <= n; ++i) {
                  for(int j = a[i]; j <= 10000; j += a[i]) {
           //通过这个循环,如果a[i]是之前一个数的因子,一定会在后边遇到 if(pre[j] != 0 && r[pre[j]] == n+1) {
              //这个数字 j (j = x * a[i])之前已经出现,且右边界是最右端 r[pre[j]] = i;   
                  //这时更新pre[j]的右端, pre[j] 表示的是 j 最后出现的位置 } } pre[a[i]] = i; //当前pre[a[i]] 最后出现的位置是 i } for(int i = n; i > 0; --i) { for(int j = a[i]; j <= 10000; j += a[i]) { if(last[j] != 0 && l[last[j]] == 0) { l[last[j]] = i; } } last[a[i]] = i; } LL ans = 0; for(int i = 1; i <= n; ++i) { ans = (LL) (ans % MOD + (LL)(((i-l[i])*(r[i]-i)%MOD)%MOD)); ans %= MOD; } cout << ans << endl; } return 0; }

 

 

你可能感兴趣的:(sequence)