1. 程式人生 > >BZOJ1590 [Usaco2008 Dec]Secret Message 秘密信息

BZOJ1590 [Usaco2008 Dec]Secret Message 秘密信息

解決 inline 有著 include com val getc ans ons

題意

貝茜正在領導奶牛們逃跑.為了聯絡,奶牛們互相發送秘密信息.

信息是二進制的,共有M(1≤M≤50000)條.反間諜能力很強的約翰已經部分攔截了這些信息,知道了第i條二進制信息的前bi(l《bi≤10000)位.他同時知道,奶牛使用N(1≤N≤50000)條密碼.但是,他僅僅了解第J條密碼的前cj(1≤cj≤10000)位.

對於每條密碼J,他想知道有多少截得的信息能夠和它匹配.也就是說,有多少信息和這條密碼有著相同的前綴.當然,這個前綴長度必須等於密碼和那條信息長度的較小者.

在輸入文件中,位的總數(即∑Bi+∑Ci)不會超過500000.

分析

參照jklover的題解。

將信息串插入 Trie 樹中,記錄子樹大小.詢問時,是密碼串前綴的,在搜索過程中會經過,密碼串是它的前綴的,到最後一個字符處加上子樹大小即可.

時間復雜度:線性。

代碼

實現起來有個細節,根節點必須是1。因為如果按密碼串匹配中途失敗之後,就不應該繼續匹配,而是一直停留在一個無效節點。所以把根節點設成1,然後無效節點自動為0,解決了這個技術問題。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read()
{
    rg T data=0,w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data*w;
}
template<class T>il T read(rg T&x)
{
    return x=read<T>();
}
typedef long long ll;
using namespace std;
co int N=5e5+1;
int tot=1,ch[N][2],val[N],siz[N];
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    int n=read<int>(),m=read<int>();
    while(n--)
    {
        int u=1,l=read<int>(); // edit 1:root must be 1
        while(l--)
        {
            int b=read<int>();
            if(!ch[u][b]) ch[u][b]=++tot;
            u=ch[u][b],++siz[u];
        }
        ++val[u],--siz[u];
    }
    while(m--)
    {
        int u=1,l=read<int>(),ans=0;
        while(l--)
        {
            int b=read<int>();
            u=ch[u][b];
            ans+=val[u];
        }
        ans+=siz[u];
        printf("%d\n",ans);
    }
    return 0;
}

BZOJ1590 [Usaco2008 Dec]Secret Message 秘密信息