洛谷:P2922 [USACO08DEC]秘密消息(Trie树)
P2922 [USACO08DEC]秘密消息Secret Message
题目链接:https://www.luogu.org/problemnew/show/P2922
题目描述
贝茜正在领导奶牛们逃跑.为了联络,奶牛们互相发送秘密信息.
信息是二进制的,共有M(1≤M≤50000)条.反间谍能力很强的约翰已经部分拦截了这些信息,知道了第i条二进制信息的前bi(l《bi≤10000)位.他同时知道,奶牛使用N(1≤N≤50000)条密码.但是,他仅仅了解第J条密码的前cj(1≤cj≤10000)位.
对于每条密码J,他想知道有多少截得的信息能够和它匹配.也就是说,有多少信息和这条密码有着相同的前缀.当然,这个前缀长度必须等于密码和那条信息长度的较小者.
在输入文件中,位的总数(即∑Bi+∑Ci)不会超过500000.
输入输出格式
输入格式:
* Line 1: Two integers: M and N
* Lines 2..M+1: Line i+1 describes intercepted code i with an integer b_i followed by b_i space-separated 0's and 1's
* Lines M+2..M+N+1: Line M+j+1 describes codeword j with an integer c_j followed by c_j space-separated 0's and 1's
输出格式:
* Lines 1..M: Line j: The number of messages that the jth codeword could match.
输入输出样例
4 5 3 0 1 0 1 1 3 1 0 0 3 1 1 0 1 0 1 1 2 0 1 5 0 1 0 0 1 2 1 1
1 3 1 1 2
题解:
直接在Trie上面匹配就行,Trie树上面记录一下以当前结点为结尾的点有多少以及有多少经过这个点就行了。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 500005; int n,m,cnt,tot; int s[N],val[N]; struct Trie{ int node,son,left,sum; }tre[N]; void init(){ tre[0].son=tre[0].left=-1;tot=1; } void insert(){ int j,u=0; for(int i=0;i<cnt;i++){ bool flag=false; for(j=tre[u].son;j!=-1;j=tre[j].left){ if(tre[j].node==s[i]){ flag=true; break ; } } if(!flag){ j=tot++; tre[j].left=tre[u].son; tre[u].son=j; tre[j].node=s[i]; tre[j].son=-1; } tre[j].sum++; u=j; } val[u]++; } int query(){ int ans = 0; int u=0,j; for(int i=0;i<cnt;i++){ bool flag=false; for(j=tre[u].son;j!=-1;j=tre[j].left){ if(tre[j].node==s[i]){ flag=true; break ; } } if(!flag) break ; if(i==cnt-1){ ans+=tre[j].sum; break ; } ans+=val[j]; u=j; } return ans ; } int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>m>>n; init(); for(int i=1;i<=m;i++){ int k,p;cnt=0; cin>>k; for(int j=1;j<=k;j++){ cin>>p; s[cnt++]=p; } insert(); } int ans = 0; for(int i=1;i<=n;i++){ ans=cnt=0;int k,p; cin>>k; for(int j=1;j<=k;j++){ cin>>p; s[cnt++]=p; } ans+=query(); cout<<ans<<'\n'; } return 0; }
重要的是自信,一旦有了自信,人就会赢得一切。