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
∑i=1n∑j=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 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
Author
FZUACM
Source
2015 Multi-University Training Contest 1
一考思维,就想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; }