BZOJ3207 花神的嘲諷(分塊解法)

題目傳送門php



題目描述:
背景
花神是神,一大癖好就是嘲諷大J,舉例以下:
「哎你傻不傻的!【hqz:大笨J】」
「這道題又被J屎過了!!」
「J這程序怎麼跑這麼快!J要逆襲了!」
……

描述
這一天DJ在給吾等衆蒟蒻講題,花神在一邊作題無聊,就跑到了一邊跟吾等衆蒟蒻一塊兒聽。如下是部分摘錄:

   「J你在講什麼!」
   「我在講XXX!」
   「哎你傻不傻的!這麼麻煩,直接XXX再XXX就行了!」
   「……」
   「J你XXX講過了沒?」
   「……」
   「那個都不講你就講這個了?哎你傻不傻的!」
   「……」

DJ對這種情景表示很是無語,往往出現這種狀況,DJ都是很是尷尬的。
↑廢話
c++



通過衆蒟蒻研究,DJ在講課以前會有一個長度爲N方案,咱們能夠把它看做一個數列;
一樣,花神在聽課以前也會有一個嘲諷方案,有M個,每次會在x到y的這段時間開始嘲諷,爲了減小題目難度,每次嘲諷方案的長度是必定的,爲K。
花神嘲諷DJ讓DJ尷尬須要的條件:
在x~y的時間內DJ沒有講到花神的嘲諷方案,即J的講課方案中的x~y沒有花神的嘲諷方案【這樣花神會嘲諷J不會因此不講】。
通過衆蒟蒻努力,在一次講課以前獲得了花神嘲諷的各次方案,DJ得知了這個消息之後欣喜不已,DJ想知道花神的每次嘲諷是否會讓DJ尷尬【說不出話來】。
spa


輸入格式:
第1行3個數N,M,K;
第2行N個數,意義如上;
第3行到第3+M-1行,每行K+2個數,前兩個數爲x,y,而後K個數,意義如上;
blog



輸出格式:
對於每個嘲諷作出一個回答會尷尬輸出‘Yes’,不然輸出‘No’
get



樣例:
樣例輸入:
8 5 3
1 2 3 4 5 6 7 8
2 5 2 3 4
1 8 3 2 1
5 7 4 5 6
2 5 1 2 3
1 7 3 4 5
樣例輸出:
No
Yes
Yes
Yes
No
hash



數據範圍與提示:
題中全部數據不超過2*10^9;保證方案序列的每一個數字<=N,n,m<=1e5,k<=20

2~5中有2 3 4的方案,輸出No,表示DJ不會尷尬

1~8中沒有3 2 1的方案,輸出Yes,表示DJ會尷尬

5~7中沒有4 5 6的方案,輸出Yes,表示DJ會尷尬

2~5中沒有1 2 3的方案,輸出Yes,表示DJ會尷尬

1~7中有3 4 5的方案,輸出No,表示DJ不會尷尬
it


一句話題意:給你m個長度爲k的串,看這m個串有沒有在主串中出現。class



題解:
終於有親切的題解啦~
我感受這是一道不錯的題,真的是一秒出正解,hash+主席樹
可是……還有可是……
主席樹挺麻煩的,何況纔剛學,懶得碼,記得分塊也能夠幹這種事,並且還能求出現的次數。
太棒啦~~~
注意這道題k是同樣的,這樣就能允許咱們用分塊啦~~~
只須要暴力求出主串全部的hash值,放進咱們分好的塊中,再用這m個串逐一查找便可
時間複雜度n√n(剛恰好)
想到這種解法以爲本身都很牛逼
程序



代碼時刻:
數據

#include<bits/stdc++.h>
using namespace std;
int n,k,m,len;
unsigned long long a[100001],b[100001],sum;//unsigned暴力卡hash
int wzc(int x){return (x-1)/k+1;}//查找這個點屬於哪一個塊
void get_hash()//主串轉hash
{
    for(int i=1;i<=n-len+1;i++)
    {
        unsigned long long sum=0;
        for(int j=i;j<=i+len-1;j++)
            sum=sum*131+a[j];
        a[i]=b[i]=sum;
    }
}
bool ask(int l,int r,unsigned long long x)//查找有沒有出現
{
    int cl=wzc(l);
    int cr=wzc(r);
    if(cl==cr)for(int i=l;i<=r;i++)if(a[i]==x)return 1;
    for(int i=l;i<=cl*k;i++)if(a[i]==x)return 1;
    for(int i=cl+1;i<cr;i++)if(upper_bound(b+(i-1)*k+1,b+i*k+1,x)-lower_bound(b+(i-1)*k+1,b+i*k+1,x))return 1;
    for(int i=(cr-1)*k+1;i<=r;i++)if(a[i]==x)return 1;
    return 0;
}
int main()
{
    scanf("%d%d%d",&n,&m,&len);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    get_hash();
    n=n-len+1;
    k=sqrt(n);
    for(int i=1;i<=k+1;i++)
    {
        if((i-1)*k+1>n)break;
        sort(b+(i-1)*k+1,b+min(i*k,n)+1);
    }
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        sum=0;
        for(int i=1;i<=len;i++)
        {
            int hs;
            scanf("%d",&hs);
            sum=sum*131+hs;
        }
        if(ask(l,r-len+1,sum))printf("No\n");//輸出要注意兩點:1.Yes和No別反了就好。2.注意大小寫!!!身邊好多同窗調了半天就由於這!!!
        else printf("Yes\n");
    }
    return 0;
}

cpp
rp++

相關文章
相關標籤/搜索