hdu 5288 OO’s Sequence 2015 Multi-University Training Contest 1

来源:互联网 发布:单片机交通灯设计步骤 编辑:程序博客网 时间:2024/06/05 07:53

这一题开始想到了枚举却忘了二分><

考虑以下case,如果Left[i]是a[i]左边最近的可以整除的因子,Right[i]是a[i]右边最近的可以整除的因子,那么这个区间就是合法区间,对ans的贡献就是[i-(Left[i]+1)+1]*[(Right[i]-1)-i+1]。

如果在二分搜索中找不到左右边界Left[i]和Right[i],即在[0,n-1]中都没有a[i]的因子,区间对ans的贡献就是[i-Left[i]+1]*[Right[i]-i+1]。这种case对应的边界是Left[i]=0,Right[i]=n-1,所以二分查找的边界应该设为l=-1,r=n。查找失败返回值恰好弥补了这种case里的+1。

另外,分解因子需要预处理,否则会TLE。也许这种O(n)的做法才是正解HDU5288 OO’s Sequence

#include<iostream>#include<stdio.h>#include<cstdio>#include<stdlib.h>#include<vector>#include<string>#include<cstring>#include<cmath>#include<algorithm>#include<stack>#include<queue>#include<ctype.h>#include<map>#include<time.h>#include<bitset>#include<set>#include<list>using namespace std;//hdu 5288const int maxn=100010;const int mod=1e9+7;int a[maxn];int n;int Left[maxn];int Right[maxn];vector<int>loc[maxn];vector<int>fact[maxn];long long ans=0;void calcfact(int x){    for(int j=1;j*j<=x;j++)    {        if(x%j==0)        {            fact[x].push_back(j);            if(x/j!=j)            {                fact[x].push_back(x/j);            }        }    }}int findleft(int x,int y){    int l=0;    int r=loc[x].size()-1;    int mid=(l+r)/2;    int ret=-1;    while(l<=r)    {        mid=(l+r)/2;        if(loc[x][mid]>=y)        {            r=mid-1;        }        else        {            l=mid+1;            if(ret<loc[x][mid])            {                ret=loc[x][mid];            }        }    }    return ret;}int findright(int x,int y){    int l=0;    int r=loc[x].size()-1;    int mid=(l+r)/2;    int ret=n;    while(l<=r)    {        mid=(l+r)/2;        if(loc[x][mid]<=y)        {            l=mid+1;        }        else        {            r=mid-1;            if(ret>loc[x][mid])            {                ret=loc[x][mid];            }        }    }    return ret;}int main(){    freopen("input.txt","r",stdin);    for(int i=0;i<maxn;i++)    {        calcfact(i);    }    while(scanf("%d",&n)!=EOF)    {        memset(a,0,sizeof(a));        memset(loc,0,sizeof(loc));        memset(Left,0,sizeof(Left));        memset(Right,0x3f,sizeof(Right));        ans=0;        for(int i=0;i<n;i++)        {            scanf("%d",&a[i]);            loc[a[i]].push_back(i);            Left[i]=-1;            Right[i]=n;        }//        for(int i=0;i<n;i++)//will lead to TLE if we calculated in every test case//        {//            calcfact(a[i]);//        }        for(int i=0;i<n;i++)        {            for(int j=0;j<fact[a[i]].size();j++)            {                int l=findleft(fact[a[i]][j],i);                int r=findright(fact[a[i]][j],i);              //  cout<<l<<" "<<r<<endl;                Left[i]=max(l,Left[i]);                Right[i]=min(r,Right[i]);            }           // cout<<endl;        }        for(int i=0;i<n;i++)        {            if((i-Left[i])==0)            {                ans=(ans+(Right[i]-i)%mod)%mod;            }            if((Right[i]-i)==0)            {                ans=(ans+(i-Left[i])%mod)%mod;            }            else            {                ans=(ans+(i-Left[i])%mod*(Right[i]-i)%mod)%mod;            }        }        printf("%I64d\n",ans);    }    return 0;}



0 0
原创粉丝点击