2016 ACM/ICPC Dalian Online-1008 Function


題意:給定長度爲n的數組A和Q個詢問。詢問[L,R],求A(L)%A(L+1)%A(L+2)%……%A(R) 。其中  1≤N,Q≤100000

一個性質:大數對小數取餘,結果小於大數的一半。所以每個大數最多對小數取log(ai)次

題解一:轉自點擊打開鏈接

已知mod操作類似gcd操作,結果是單調的,只會小不會大。

把所有詢問預存,按左邊界排序,當前左邊界存在於詢問時,加入優先隊列,對於當前位置,優先隊列中大於a[i]的都對a[i]取餘,取到 < a[i]即可停止,更小的肯定更無變化,根據右邊界拋出即可

複雜度爲O(nlgnlgn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>

using namespace std;

const int N=1e5+10;

struct Node{
    int R,v,n;
    Node(){}
    Node(int R,int v,int n):R(R),v(v),n(n){}
    bool operator <(const Node&a)const{
        return v<a.v;
    }
};
struct Sec{
    int L,R,n;
    Sec(){}
    Sec(int L,int R,int n):L(L),R(R),n(n){}
}c[N];

int a[N],n,m;
int Ans[N];
priority_queue<Node>Q;
bool cmp(Sec i,Sec j){return i.L<j.L;}
void work()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)scanf("%d",&a[i]);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)scanf("%d%d",&c[i].L,&c[i].R),c[i].n=i;

    sort(c+1,c+m+1,cmp);

    int cNow=1;
    for (int i=1;i<=n;i++){
        while (!Q.empty()){
            Node tmp=Q.top();
            if (i>tmp.R){Ans[tmp.n]=tmp.v;Q.pop();}else
            if (tmp.v>=a[i]){//a[i]==0
                Q.pop();
                Q.push(Node(tmp.R,tmp.v%a[i],tmp.n));
            }else break;
        }
        while (cNow<=m && c[cNow].L==i){
            Q.push(Node(c[cNow].R,a[i],c[cNow].n));
            cNow++;
        }
    }
    while (!Q.empty()){
        Node tmp=Q.top();Q.pop();
        Ans[tmp.n]=tmp.v;

    }
    for (int i=1;i<=m;i++)printf("%d\n",Ans[i]);
}
int main()
{
    //freopen("1.txt","r",stdin);
    int Case;scanf("%d",&Case);
    while (Case--)work();
    return 0;
}


題解二:對於詢問i,每次尋找值小於等於當前值的最近位置pos,不斷取模,直到pos>R或者找不到這樣的值爲止。

      對於尋找,用線段樹,區間[L,R]表示a(i)的值爲[L,R]時的最小位置。由於可能位置在L之前,所以我們可以對詢問按左邊界L從小到大排序。枚舉位置(i-1)->i時,除去a(i)在線段樹中的值,可以用下一個值爲a(i)的點覆蓋。

處理時需要先對A離散化。複雜度爲O(nlgnlgn)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>

using namespace std;

const int N=1e5+10;

struct Sec{
    int L,R,n;
    Sec(){}
    Sec(int L,int R,int n):L(L),R(R),n(n){}
}c[N];

int a[N],n,m;
int d[N],dn;
int T[N<<2];
int Ans[N];
int nxt[N],Head[N];
bool cmp(Sec i,Sec j){return i.L<j.L;}
void WZJ()
{
    for (int i=1;i<=n;i++)d[i]=a[i];
    sort(d+1,d+n+1);
    dn=unique(d+1,d+n+1)-(d+1);
    for (int i=1;i<=n;i++)
        a[i]=lower_bound(d+1,d+dn+1,a[i])-d;
}
void Insert(int p,int L,int R,int pos,int v)
{
    if (L==R){T[p]=v;return ;}
    int mid=(L+R)>>1;
    if (pos<=mid)Insert(p<<1,L,mid,pos,v);
    else Insert(p+p+1,mid+1,R,pos,v);
    T[p]=min(T[p+p],T[p+p+1]);
}
int Find(int p,int L,int R,int v)
{
    if (R<=v)return T[p];
    int mid=(L+R)>>1;
    if (v<=mid)return Find(p+p,L,mid,v);
    else return min(T[p+p],Find(p+p+1,mid+1,R,v));
}
void Look(int p,int L,int R)
{
    printf("%d %d %d\n",L,R,T[p]);
    if (L==R)return ;
    int mid=(L+R)>>1;
    Look(p+p,L,mid);
    Look(p+p+1,mid+1,R);
}
void work()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)scanf("%d",&a[i]);
    WZJ();

    memset(Head,0,sizeof Head);
    for (int i=n;i>=1;i--){
        nxt[i]=Head[a[i]];
        Head[a[i]]=i;
    }

    for (int i=1;i<(n<<2);i++)T[i]=dn+1;
    for (int i=1;i<=dn;i++)
        Insert(1,1,dn,a[Head[i]],Head[i]);

    scanf("%d",&m);
    for (int i=1;i<=m;i++)scanf("%d%d",&c[i].L,&c[i].R),c[i].n=i;
    sort(c+1,c+m+1,cmp);

    int cNow=1;
    for (int i=1;i<=n;i++){
        if (nxt[i]==0)Insert(1,1,dn,a[i],n+1);
        else Insert(1,1,dn,a[i],nxt[i]);

        for (;cNow<=m && c[cNow].L==i;cNow++){
            int v=d[a[i]],R=c[cNow].R;
            while (1){
                int tmp=upper_bound(d+1,d+dn+1,v)-d-1;
                if (tmp==0) break;
                int pos=Find(1,1,dn,tmp);
                if (pos>R)break;
                v=v%d[a[pos]];
            }
            Ans[c[cNow].n]=v;
        }
    }

    for (int i=1;i<=m;i++)printf("%d\n",Ans[i]);
}
int main()
{
    //freopen("1.txt","r",stdin);
    int Case;scanf("%d",&Case);
    while (Case--)work();
    return 0;
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章