【STSRM12】整除

【题意】给定长度为n的序列A,求最长的区间满足区间内存在数字能整除区间所有数字,同时求所有方案。n<=5*10^5,Ai<2^31。

【算法】数论???

【题解】首先一个区间的基准数一定是最小的数字。

以一个数字为基准数,左右扩展到的区间内的数字都不能再作为基准数(不会超过此时的区间,为同一个)。

从小到大选取基准数并左右扩展(标记),标记过的不再作为基准数。

复杂度O(n log n)。(排序的复杂度)

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=500010;
int a[maxn],p[maxn],n,ans,ansx,b[maxn];
bool vis[maxn];
bool cmp(int x,int y){return a[x]<a[y];}
void work(int x){
    if(vis[x])return;
    int l,r;
    for(l=x;l>=1&&a[l]%a[x]==0;l--)vis[l]=1;
    for(r=x;r<=n&&a[r]%a[x]==0;r++)vis[r]=1;
//    printf("l=%d r=%d\n",l,r);
    if(r-l-2>ans){ans=r-l-2;p[ansx=1]=l+1;}
    else if(r-l-2==ans){p[++ansx]=l+1;}
}    
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){scanf("%d",&a[i]);b[i]=i;}
    sort(b+1,b+n+1,cmp);
    for(int i=1;i<=n;i++)work(b[i]);
    sort(p+1,p+ansx+1);
    printf("%d %d\n",ansx,ans);
    for(int i=1;i<=ansx;i++)printf("%d ",p[i]);
    return 0;
}
View Code

 

posted @ 2017-08-10 16:38  ONION_CYC  阅读(149)  评论(0编辑  收藏  举报