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 imod a j=0,now OO want to know [∑i=1n ∑j=i n f(i,j) ] mod (10^9+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
题意:给出长度为n的数列,设函数f(i,j)表示,在a[i]到a[j]中,其中i<=ti<=j,满足a[ti]%a[tj]!=0的ti的个数,其中tj为不等于ti的任意 i 到 j 中的数。
求出 [∑i=1n ∑j=i n f(i,j) ] mod (10^9+7)。
思路:对于数列中的每一个数,求出其被所有可行区间包含的次数。
代码与注释如下。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; const int maxn=10005,maxx=100005; const long long mod=1000000007; vector<int>divi[maxn]; int a[maxx],l[maxx],r[maxx],pos[maxn],n; void ini(){ for(int i=1;i<=10000;i++) for(int j=1;j<=i;j++) if(i%j==0) divi[i].push_back(j); //预处理出10000内所有数的因子 } int main(){ ini(); while(~scanf("%d",&n)){ for(int i=0;i<n;i++) scanf("%d",&a[i]); memset(l,-1,sizeof(l)); memset(r,0x3f,sizeof(r)); memset(pos,-1,sizeof(pos)); //l[i]表示a[i]左边与之最接近的它的因子的下标 for(int i=0;i<n;i++){ int lef=-1; for(int j=0;j<divi[a[i]].size();j++) lef=max(lef,pos[divi[a[i]][j]]); pos[a[i]]=i; //pos数组用于更新维护最靠近a[i]的因子数的下标 l[i]=lef; } memset(pos,0x3f,sizeof(pos)); //r[i]表示a[i]右边与之最接近的它的因子的下标 for(int i=n-1;i>=0;i--){ int rig=0x3f3f3f3f; for(int j=0;j<divi[a[i]].size();j++) rig=min(rig,pos[divi[a[i]][j]]); pos[a[i]]=i; //pos数组用于更新维护最靠近a[i]的因子数的下标 r[i]=rig; } long long ans=0,L,R; for(int i=0;i<n;i++){ if(l[i]==-1) L=i+1; //若为原值,则说明a[i]左边不存在因子 else L=i-l[i]; //否则,令L为a[i]到其因子右边第一个数之间的个数 if(r[i]==0x3f3f3f3f) R=n-i; else R=r[i]-i; ans=(L*R%mod+ans)%mod; //L*R为包含a[i]的连续区间的组合数。 } printf("%d\n",ans); } return 0; }
时间: 2024-10-22 18:11:41