2015 Multi-University Training Contest 1 1001
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 Problem: HDU-5288,多校#1 1001 3 Tips: 数学。思路 4 Date: 2015.7.29 5 题意: 给出含n个元素的数组a,问所有区间中,满足对该区间所有aj(j!=i),都使ai%aj!=0的i的个数; 6 分析: 对于a[i],找到左右两边离它最近的因子的位置lp[i],rp[i],(没有的话就分别设为0/(n+1)),那么a[i]在仅会在(rp[i]-i)*(i-lp[i])个区间内出现 7 注意: 求lp, rp的算法,小心超时! 8 */ 9 10 11 #include<iostream> 12 #include<cstdio> 13 #include<cstdlib> 14 #include<cmath> 15 #include<vector> 16 #include<map> 17 #include<cstring> 18 using namespace std; 19 typedef long long ll; 20 const int maxn = 100010; 21 const int M = 10010; 22 const ll MOD = 1000000007; 23 int n, a[maxn]; 24 25 vector<int> fac[M]; 26 int lp[maxn], rp[maxn], pre[M]; 27 void get_fac() //储存1~10000所有数的因子 28 { 29 for(int i = 1; i < M; i++) 30 for(int j = 1; j*j <= i; j++) 31 if(i % j == 0) 32 { 33 if(j * j != i) fac[i].push_back(i / j); 34 fac[i].push_back(j); 35 } 36 } 37 38 int main() 39 { 40 get_fac(); 41 while(~scanf("%d", &n)) 42 { 43 for(int i = 1; i <= n; i++) 44 scanf("%d", &a[i]); 45 46 memset(pre, 0, sizeof(pre));//pre数组记录数字i所在(上一个)位置 47 for(int i = 1; i <= n; i++) //找左边因子位置 48 { 49 int u = a[i], pos = 0; //pos记录左边最靠近i的因子位置 50 for(int j = 0; j < fac[u].size(); j++) 51 { 52 int v = fac[u][j]; 53 pos = max(pos, pre[v]); 54 } 55 lp[i] = pos; 56 pre[u] = i; 57 } 58 59 memset(pre, 0x3f, sizeof(pre)); //pre数组记录数字i所在(上一个)位置 60 for(int i = n; i >= 1; i--) //找右边因子位置 61 { 62 int u = a[i], pos = n+1; //pos记录右边最靠近i的因子位置 63 for(int j = 0; j < fac[u].size(); j++) 64 { 65 int v = fac[u][j]; 66 pos = min(pos, pre[v]); 67 } 68 rp[i] = pos; 69 pre[u] = i; 70 } 71 72 ll res = 0; 73 for(int i = 1; i <= n; i++) 74 { 75 res += (ll)((rp[i]-i) * (i-lp[i])) % MOD; 76 } 77 printf("%lld ", res % MOD); 78 } 79 return 0; 80 }