【题意】给定长度为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 ",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 ",ansx,ans); for(int i=1;i<=ansx;i++)printf("%d ",p[i]); return 0; }