CodeForces 359D (數論+二分+ST演算法)

來源:互聯網
上載者:User

標籤:style   blog   http   color   io   os   使用   ar   for   

題目連結: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=47319

題目大意:給定一個序列,要求確定一個子序列,①使得該子序列中所有值都能被其中一個值整除,②且子序列範圍儘可能大(r-l儘可能大)。

解題思路:

對於要求1,不難發現只有min(L,R)=gcd(L,R)時才行。其中gcd是L,R範圍內的最大公約數,min是L,R範圍內的最小值。

對於要求2,傳統思路是r-l從大到小枚舉,每次確定一個(L,R)範圍,進行判斷,直到可行。複雜度O(n^2)鐵定TLE。

由於r-l的值是有序的,固採用二分。先枚舉r-l的中間值,如果符合要求,則向右考慮,看看有沒有更大的。否則向左。

當然這題的難度不止於此,儘管採用二分,但是光是枚舉複雜度就有O(nlogn)了,再加上查詢orz。

最初我使用的是線段樹完成RMQ、以及GCD的Query , 複雜度O(n*logn*logn), CF跑到Test10就TLE了。

看了題解才發現要使用ST演算法在O(1)的時間內完成RMQ和GCD。也是第一次碰到ST演算法,看見劉汝佳的炒雞簡潔ST,給跪了。

 

#include "cstdio"#include "iostream"#include "vector"#include "algorithm"#include "math.h"#include "cstring"using namespace std;#define lson l,mid,root<<1#define rson mid+1,r,root<<1|1#define maxn 3*100005#define maxp 20template <class T>inline bool read(T &ret){    char c;    int sgn;    if(c=getchar(),c==EOF) return 0; //EOF    while(c!=‘-‘&&(c<‘0‘||c>‘9‘)) c=getchar();    sgn=(c==‘-‘)?-1:1;    ret=(c==‘-‘)?0:(c-‘0‘);    while(c=getchar(),c>=‘0‘&&c<=‘9‘) ret=ret*10+(c-‘0‘);    ret*=sgn;    return 1;}int gcd(int a,int b) {if(b!=0) return gcd(b,a%b);else return a;}int RMQ[maxn][maxp],GCD[maxn][maxp],val[maxn],n,cnt,range;vector<int> ans;void ST(){    for(int i=1;i<=n;i++) RMQ[i][0]=GCD[i][0]=val[i];    for(int j=1;(1<<j)<=n;j++)        for(int i=1;i+(1<<j)-1<=n;i++)    {        RMQ[i][j]=min(RMQ[i][j-1],RMQ[i+(1<<(j-1))][j-1]);        GCD[i][j]=gcd(GCD[i][j-1],GCD[i+(1<<(j-1))][j-1]);    }}bool Query(int L,int R){    int k=0;    while((1<<(k+1))<=R-L+1) k++;    int a=min(RMQ[L][k],RMQ[R-(1<<k)+1][k]);    int b=gcd(GCD[L][k],GCD[R-(1<<k)+1][k]);    if(a==b) return true;    else return false;}bool judge(int v) //枚舉r-l{    int cc=0;    vector<int> tt;    for(int i=1; v+i<=n; i++)    {        if(Query(i,i+v)) //L=i,R=i+v;        {            cc++;            tt.push_back(i);        }    }    if(cc>0)    {        ans=tt;        cnt=cc;        range=v;        return true;    }    return false;}int main(){    memset(RMQ,1,sizeof(RMQ));    memset(GCD,1,sizeof(GCD));    read(n);    for(int i=1; i<=n; i++)        read(val[i]);    ST();    int l=0,r=n-1,mid;    while(l<=r)  //二分    {        mid=(l+r)>>1;        if(judge(mid)) l=mid+1;        else r=mid-1;    }    printf("%d %d\n",cnt,range);    for(int i=0;i<ans.size();i++) {if(i>0) printf(" ");printf("%d",ans[i]);};    printf("\n");}

 

2808336 neopenx CodeForces 359D Accepted 51924 KB 327 ms GNU C++ 4.6 1976 B 2014-10-03 14:55:49  

 

   

 

CodeForces 359D (數論+二分+ST演算法)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.