BZOJ 2462: [BeiJing2011]矩阵模板
2016-03-28 21:17
288 查看
Description
给定一个M行N列的01矩阵,以及Q个A行B列的01矩阵,你需要求出这Q个矩阵哪些在原矩阵中出现过。
所谓01矩阵,就是矩阵中所有元素不是0就是1。
Input
输入文件的第一行为M、N、A、B,参见题目描述。
接下来M行,每行N个字符,非0即1,描述原矩阵。
接下来一行为你要处理的询问数Q。
接下来Q个矩阵,一共Q*A行,每行B个字符,描述Q个01矩阵。
Output
你需要输出Q行,每行为0或者1,表示这个矩阵是否出现过,0表示没有出现过,1表示出现过。
HINT
对于100%的数据,A < = 100。
还是想不通为什么数据这么水。。。其实我的程序有个bug,今天考完试才发现,成绩发下来居然水过了,,无语。。
下面说说思路首先字符总数不大,而且字符串较多,且是01串,情况数较少,,一看就是AC自动机啊,对于每一个询问的子矩阵,每行为一个字符串,建一个AC自动机,然后将原矩阵的各行作为一个字符串进行匹配;每匹配一个字符串,就记录下字矩阵的改行是由原矩阵的哪行匹配成功的,,这里由于匹配的数量不知,因此用vector或者直接手动开个栈也行(毕竟数据太弱),,注意,除了字矩阵的第一行外,字矩阵其余行都要在该行的前一行与原矩阵当前行的前一行匹配成功时才记录下匹配信息;直到原矩阵的最后一行如果也匹配成功,,则该矩阵存在于原矩阵中。。
不知道你们有没有发现bug,,那就是匹配矩阵时我只记录了匹配成功的行数信息,保证了每一行都是连续的,,却没有保证列的连续,,因此匹配时有可能发生错位。只要在记录行数的同时再记录一下列数就能解决这个问题了。
以下代码未经修改,,但BZOJ也能水过,有兴趣的可以自己把bug填好。(反正劳资没兴趣。你们随意。)
给定一个M行N列的01矩阵,以及Q个A行B列的01矩阵,你需要求出这Q个矩阵哪些在原矩阵中出现过。
所谓01矩阵,就是矩阵中所有元素不是0就是1。
Input
输入文件的第一行为M、N、A、B,参见题目描述。
接下来M行,每行N个字符,非0即1,描述原矩阵。
接下来一行为你要处理的询问数Q。
接下来Q个矩阵,一共Q*A行,每行B个字符,描述Q个01矩阵。
Output
你需要输出Q行,每行为0或者1,表示这个矩阵是否出现过,0表示没有出现过,1表示出现过。
HINT
对于100%的数据,A < = 100。
还是想不通为什么数据这么水。。。其实我的程序有个bug,今天考完试才发现,成绩发下来居然水过了,,无语。。
下面说说思路首先字符总数不大,而且字符串较多,且是01串,情况数较少,,一看就是AC自动机啊,对于每一个询问的子矩阵,每行为一个字符串,建一个AC自动机,然后将原矩阵的各行作为一个字符串进行匹配;每匹配一个字符串,就记录下字矩阵的改行是由原矩阵的哪行匹配成功的,,这里由于匹配的数量不知,因此用vector或者直接手动开个栈也行(毕竟数据太弱),,注意,除了字矩阵的第一行外,字矩阵其余行都要在该行的前一行与原矩阵当前行的前一行匹配成功时才记录下匹配信息;直到原矩阵的最后一行如果也匹配成功,,则该矩阵存在于原矩阵中。。
不知道你们有没有发现bug,,那就是匹配矩阵时我只记录了匹配成功的行数信息,保证了每一行都是连续的,,却没有保证列的连续,,因此匹配时有可能发生错位。只要在记录行数的同时再记录一下列数就能解决这个问题了。
以下代码未经修改,,但BZOJ也能水过,有兴趣的可以自己把bug填好。(反正劳资没兴趣。你们随意。)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; struct node { int ch[2],file;vector<int> count; node() { file=ch[0]=ch[1]=0; } }t[1000010]; int head,ans,m,n,a,tot,b,dl[101][1001];char str[1001][1001]; void insert(char str[],int j) { int now=head;int i=0; while(i<b) { int d=str[i]-'0'; if(t[now].ch[d]==0) t[now].ch[d]=tot++; now=t[now].ch[d];i++; } t[now].count.push_back(j);return; } void bfs() { int now=head,point=1; queue<int> q; t[head].file=head; for(int i=0;i<=1;i++) { if(t[head].ch[i]) { q.push(t[head].ch[i]); t[t[head].ch[i]].file=head; } else t[head].ch[i]=head; } while(!q.empty()) { int x=q.front();q.pop(); for(int i=0;i<=1;i++) { if(t[x].ch[i]) { q.push(t[x].ch[i]);point=t[x].file; while(t[point].ch[i]==0&&point!=head) point=t[now].file; t[t[x].ch[i]].file=t[point].ch[i]; } else t[x].ch[i]=t[t[x].file].ch[i]; } } } void mark(int now,int j) { int l=t[now].count.size(); for(int i=0;i<l;i++) { int x=t[now].count[i]; if(x==1) { dl[x][++dl[x][0]]=j; if(x==a) ans=1;continue; } if(dl[x-1][0]==0) continue; if(dl[x-1][dl[x-1][0]]==j-1||dl[x-1][dl[x-1][0]-1]==j-1) { dl[x][++dl[x][0]]=j; if(x==a) ans=1; } } return; } void find(char str[],int j) { int now=head,i=0; while(i<n) { int d=str[i++]-'0'; if(t[now].ch[d]) now=t[now].ch[d]; else { while(!t[now].ch[d]&&now!=head) now=t[now].file;now=t[now].ch[d]; } if(t[now].count.size()) mark(now,j); } } int main() { scanf("%d%d%d%d",&m,&n,&a,&b);tot=1; for(int i=1;i<=m;i++) { scanf("%s",str[i]); } int q;scanf("%d",&q); if(b>n||a>m) { while(q--) printf("0\n") 4000 ;return 0; } for(int i=1;i<=q;i++) { ans=0;head=tot++; for(int j=0;j<=a;j++) dl[j][0]=0; for(int j=1;j<=a;j++) { scanf("%s",&str[0]);insert(str[0],j); } bfs(); for(int j=1;j<=m;j++) { if(!ans) find(str[j],j); } printf("%d",ans);if(i!=q) printf("\n"); } }
相关文章推荐
- 数据库链接字符串查询网站
- Flex字符串比较 还有Flex字符串操作
- Ruby中创建字符串的一些技巧小结
- ASP下经常用的字符串等函数参考资料
- 将字符串小写转大写并延时输出的批处理代码
- 将字符串转换成System.Drawing.Color类型的方法
- Lua源码中字符串类型的实现
- Lua性能优化技巧(四):关于字符串
- 字符串聚合函数(去除重复值)
- Ruby中的字符串编写示例
- 总结的5个C#字符串操作方法分享
- sqlserver中求字符串中汉字的个数的sql语句
- sql server字符串非空判断实现方法
- VBS的字符串及日期操作相关函数
- C#实现将千分位字符串转换成数字的方法
- jquery 删除字符串最后一个字符的方法解析
- PowerShell实现在字符串中查找大写字母
- PowerShell中使用Out-String命令把对象转换成字符串输出的例子
- PowerShell中字符串使用单引号和双引号的区别
- Powershell小技巧之获取字符串的行数