JLOI棋局定式
在“jloi-08”游戏中,还存有非常非常多的棋局定式,也就是常会用到的下棋的组合。有时在学习一个著名棋局时,电脑会考一考刘先生:在这局棋里面,有多少个定式啊?分别是什么啊?
对于30~40步的普通棋局,刘先生还能回答出来,可是有时候2个实力相当的大牛下的棋局,2000000步都有可能。如果电脑对这样的棋局提上面的问题时,刘先生就必须写一个程序来帮助自己了。可是,刘先生在这方面却…,怎么写也写不对。你能帮助刘先生吗?
棋局是由很多step组成的,而step是由一个字符串组成的,比如Kh2或者是Nxb7。
前者表示K(king)移动至h2格,后者表示N(knight)移动至b7格并吃掉原有的棋子。
第一个字符可能有6种:K Q B N R P,而后面可能是一个坐标或者是字符x后跟一个坐标。
坐标是由一个小写英文字母(a~h)和一个数字(1~8)组成的。
如果一个棋局中完整地并连续地包含一个定式中所有的step,那么这个棋局便包含这个定式。
输入格式:
第一行2个整数n, m,表示定式的个数(1<=n<=2000)以及这个棋局所包含的步数
下面的n个块(block),每块包含:
第一行一个整数k表示定式包含的步数(1<=k<=100000, ∑k<=200000)
第二行一个字符串表示该定式的名称(长度不超过50)
下面的k行每行一个字符串表示定式中的一步
最后的m行每行一个字符串,表示棋局中的一步
输出格式:
按照输入文件包含的定式的顺序,输出棋局包含的所有定式的名称,一个一行。
样例输入:
2 5
3
King’s Knight Opening
Pe4
Pe5
Nf3
3
Nimzowitsch Variation
Pc4
Pe5
Nf3
Pe4
Pe5
Nf3
Nc6
Bb5
样例输出:
King’s Knight Opening
时间限制:
1000
空间限制:
512000
裸的AC自动机,复习了一下。结果常数写太大,过不了—
%:pragma GCC optimize(4)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<cstdlib>
#include<queue>
#include<new>
using namespace std;
#define N 1000001
int n,m;
struct AK_machine{
int fail[N];
bool vis[N];
int sz,root;
char mark[2001][2001];
char xv[2001];
int move[2001][2001];
int redance[2000001];
int len[2001];
int cnt;
vector<int>num[N];
int ans;
char c;
map<int,int>son[N];
map<int,int>::iterator it;
int hash[128][128][128];
int clf[N];
int KO;
void init()
{
for(int i=1;i<=10000;i++)son[0][i]=1;
root=++sz;
cnt=0;ans=0;KO=0;
}
void add(int x)
{
scanf("%d",&len[x]);
c=1;
while(c!=10)c=getchar();
cin.getline(mark[x],10001);
int p=root;
for(int i=1;i<=len[x];i++)
{
int l=0;
c=1;
while(c!=10)
{
c=getchar();if(c!=10)xv[l++]=c;
}
// scanf("%s",xv);
if(l==2){xv[2]=xv[1];xv[1]='#';}
if(!hash[xv[0]][xv[1]][xv[2]]) hash[xv[0]][xv[1]][xv[2]]=++cnt;
move[x][i]=hash[xv[0]][xv[1]][xv[2]];
if(!son[p][move[x][i]])
{
son[p][move[x][i]]=++sz;
}
p=son[p][move[x][i]];
}
num[p].push_back(x);
}
void dance()
{
queue<int>q;
while(!q.empty())q.pop();
q.push(root);
fail[root]=0;
while(!q.empty())
{
int xx=q.front();q.pop();
for(it=son[xx].begin();it!=son[xx].end();it++)
{
int a=it->first;
int b=it->second;
int u=fail[xx];
while(!son[u].count(a)) u=fail[u];
fail[b]=son[u][a];
q.push(b);
}
}
}
void doit()
{
for(int i=1;i<=m;i++)
{
int l=0;
scanf("%s",xv);
if(strlen(xv)==2){xv[2]=xv[1];xv[1]='#';}
if(!hash[xv[0]][xv[1]][xv[2]]) hash[xv[0]][xv[1]][xv[2]]=++cnt;
redance[i]=hash[xv[0]][xv[1]][xv[2]];
}
int temp=root,u=root,a,b,p=root;
for(int i=1;i<=m;i++)
{
int k=redance[i];
while(!son[p].count(k)) p=fail[p];
p=son[p][k];
temp=p;
while(temp)
{
if(!vis[temp])
{
int ll=num[temp].size();
for(int j=0;j<ll;j++)
{
clf[++ans]=num[temp][j];
}
vis[temp]=1;
}
temp=fail[temp];
}
}
sort(clf+1,clf+ans+1);
for(int k=1;k<=ans-1;k++)
{
int l=strlen(mark[clf[k]]);
for(int j=0;j<l;j++) putchar(mark[clf[k]][j]);
puts("");
}
int l=strlen(mark[clf[ans]]);
for(int j=0;j<l;j++) putchar(mark[clf[ans]][j]);
}
} fire_dancer;
int main()
{
scanf("%d%d",&n,&m);
fire_dancer.init();
for(int i=1;i<=n;i++) fire_dancer.add(i);
fire_dancer.dance();
fire_dancer.doit();
}
MAP STL划水记,我们如果用!的形式就会强行增加一个元素,所以应该用count才能A