【数论,思路】HDU-5288;多校#1-1001

Posted on 2015-07-29 12:00  LLGemini  阅读(183)  评论(0编辑  收藏  举报

2015 Multi-University Training Contest 1  1001

 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\n", res % MOD);
78     }
79     return 0;
80 }
View Code