题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5288
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=1->n)∑(j=i->n)f(i,j) mod (109+7).
题意:给一个大小为n的数组a[i]以及n各数,求所有f(le,ri)的和([le,ri]是[1,n]的所有子区间),f(le,ri)是指区间[le,ri]里每一个满足一定条件的a[i]的个数,
条件是区间[le,ri]里没有一个不等于i的j使得a[i]%a[j]=0;(如果le==ri,区间只有一个a[i],这个是满足条件的,因为确实是没有一个不等于i的j,那就更不用谈什么模了。)
思路:数据大,暴力无解,从a[i]%a[j]=0入手,这样的a[j]一定是a[i]的因子,也就是说一个区间一旦有了a[i]的因子a[i]对答案就没有贡献了,那么对于每一个a[i]
向两边扩张区间,遇到离a[i]最近的一个因子,存下位置le[i],ri[i],那么a[i]有用的最大区间就是[le[i],ri[i]],然后这个怎么算a[i]对答案的贡献,只要在这个区间包含到a[i]
的所有子区间都满足条件并且贡献答案1,那么就算包含a[i]的区间个数,既然包含a[i],那么子区间的起点le可以从le[i]取到i,终点从i取到ri[i],总共有(i-le[i])*(ri[i]-i)个;
这样还有个问题,如从i开始直接往两边去一个一个找端点还是会超时的,需要优化,a[i]只有10000,不大因子个数也不多,那么用筛法的思想对每个数把其位置添加到这个数的
倍数后面,以表示它的倍数有这个因子;
1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<algorithm> 5 #include<set> 6 #include<map> 7 #include<queue> 8 #include<vector> 9 #include<iterator> 10 #include<utility> 11 #include<sstream> 12 #include<iostream> 13 #include<cmath> 14 #include<stack> 15 using namespace std; 16 const int INF=1000000007; 17 const double eps=0.00000001; 18 const int maxn=1e5+5; 19 const int mod=1e9+7; 20 typedef __int64 ll; 21 typedef struct 22 { 23 int val,pos; 24 }aa; 25 aa a[maxn]; 26 int l[maxn],r[maxn]; 27 vector<int> v[10005];//保存每个数i的因子的在a[]数组里的下标 28 bool cmp(aa x,aa y) 29 { 30 if(x.val==y.val)//注意如果有相同的数,优先前面的,为了找到最近的因子 31 return x.pos<y.pos; 32 return x.val<y.val; 33 } 34 int main() 35 { 36 int n; 37 while(~scanf("%d",&n)) 38 { 39 ll ans=0; 40 for(int i=1;i<=n;i++) 41 scanf("%d",&a[i].val),a[i].pos=i; 42 for(int i=1;i<=10005;i++) v[i].clear(); 43 for(int i=1;i<=n;i++) 44 l[i]=0,r[i]=n+1; 45 //用结构体存了下标对应的数,排序是为找因子 46 //每个数的因子一定小于等于它,因子先出现放在前面; 47 //当考虑到一个数的时候,它的因子已经全部找出来了 48 sort(a,a+n,cmp); 49 for(int i=1;i<=n;i++) 50 { 51 int tmp=a[i].val; 52 for(int j=tmp;j<=10000;j+=tmp)//添加因子,数不多 53 v[j].push_back(a[i].pos); 54 } 55 for(int i=1;i<=n;i++) 56 { 57 int tmp=a[i].val; 58 for(int j=v[tmp].size()-1;j>=0;j--)//暴搜所有因子的位置,找最近的 59 { 60 if(v[tmp][j]<a[i].pos) l[a[i].pos]=max(l[a[i].pos],v[tmp][j]); 61 if(v[tmp][j]>a[i].pos) r[a[i].pos]=min(r[a[i].pos],v[tmp][j]); 62 } 63 } 64 for(int i=1;i<=n;i++) 65 { 66 int t=a[i].pos; 67 ans=(ans+(ll)(a[i].pos-l[a[i].pos])*(r[a[i].pos]-a[i].pos))%mod; 68 } 69 printf("%I64d\n",ans); 70 } 71 return 0; 72 }
原文:http://www.cnblogs.com/2445512490wh/p/4675032.html