题目描述
一张n*m的方格纸,有些格子需要印成黑色,剩下的格子需要保留白色。你有一个a*b的印章,有些格子是凸起(会沾上墨水)的。你需要判断能否用这个印章印出纸上的图案。印的过程中需要满足以下要求:(1)印章不可以旋转。(2)不能把墨水印到纸外面。(3)纸上的同一个格子不可以印多次。
输入输出格式
输入格式:第一行一个整数q(1<=q<=10),表示测试点数量。接下来q个测试点,每个测试点中:第一行包含4个整数n,m,a,b(1<=n,m,a,b<=1000)。接下来n行,每行m个字符,描述纸上的图案。'.'表示留白,'x'表示需要染黑。接下来a行,每行b个字符,描述印章。'.'表示不沾墨水,'x'表示沾墨水。
输出格式:对于每个测试点,输出TAK(是)或NIE(否)。
输入输出样例
2 3 4 4 2 xx.. .xx. xx.. x. .x x. .. 2 2 2 2 xx xx .x x.
TAK NIE
说明
一张n*m的方格纸,有些格子需要印成黑色,剩下的格子需要保留白色。
你有一个a*b的印章,有些格子是凸起(会沾上墨水)的。你需要判断能否用这个印章印出纸上的图案。印的过程中需要满足以下要求:
(1)印章不可以旋转。
(2)不能把墨水印到纸外面。
(3)纸上的同一个格子不可以印多次。
提交地址 : Luogu3585;
模拟水题;
调了半天(真是半天);
首先,我们肯定要把印章的左上角第一个有印的地方,对准画布上第一个左上角地方;
显然可以暴力O(n^4), T飞;
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; inline char nc() { static const int BS = 1 << 22; static unsigned char buf[BS],*st,*ed; if(st == ed) ed = buf + fread(st=buf,1,BS,stdin); return st == ed ? EOF : *st++; } //#define getchar nc inline int read() { int res=0;bool flag=0;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')flag=1;ch=getchar(); }while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch-'0');ch=getchar(); }return flag?-res:res; } int q; int n, m, x, y; int a[1010][1010]; int tab[1010][1010]; int num, fx, fy; bool check(int xx, int yy) { xx -= fx - 1, yy -= fy - 1; for (register int i = 1 ; i <= x ; i ++) { for (register int j = 1 ; j <= y ; j ++) { if (tab[i][j] == 0) continue; if (xx + i - 1 <= 0 or xx + i - 1 > n or yy + j - 1 <= 0 or yy + j - 1 > m or a[xx+i-1][yy+j-1] == 0) return 0; a[xx+i-1][yy+j-1] = 0; num--; } } return 1; } int main() { q = read(); while (q--) { num=0; n=read(), m=read(), x=read(), y=read(); fx = fy = 0; for (register int i = 1 ; i <= n ; i ++) { for (register int j = 1 ; j <= m ; j ++) { char ch; cin >> ch; if (ch == '.') a[i][j] = 0; else a[i][j] = 1, num++; } } for (register int i = 1 ; i <= x ; i ++) { for (register int j = 1 ; j <= y ; j ++) { char ch; cin >> ch; if (ch == '.') tab[i][j] = 0; else { tab[i][j] = 1; if (!fx) fx = i, fy = j; } } } for (register int i = 1 ; i <= n ; i ++) { for (register int j = 1 ; j <= m ; j ++) { if (!a[i][j]) continue; if (!check(i, j)) { puts("NIE"); goto End; } if (num == 0) { puts("TAK"); goto End; } } } puts("NIE"); End:; } return 0; }
现在我们考虑优化;
我们把时间主要浪费在哪里了?
不停地循环找印章!
显然我们在印章和图里有很多不需要的点, 我们花费了太多时间浪费在它们身上;
那不如干脆来一个链表,直接把有用的点穿起来,这样查询十分省时间!
轻松A掉
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 7 inline char nc() 8 { 9 static const int BS = 1 << 22; 10 static unsigned char buf[BS],*st,*ed; 11 if(st == ed) ed = buf + fread(st=buf,1,BS,stdin); 12 return st == ed ? EOF : *st++; 13 } 14 #define nc getchar 15 inline int read() 16 { 17 int res=0;bool flag=0;char ch=nc(); 18 while(!isdigit(ch)){if(ch=='-')flag=1;ch=nc(); 19 }while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch-'0');ch=nc(); 20 }return flag?-res:res; 21 } 22 23 int q; 24 int n, m, x, y; 25 struct MAP 26 { 27 int x, y; 28 }a[1010*1010]; 29 int cnt = 1; 30 struct TAB 31 { 32 int x, y; 33 }tab[1010*1010]; 34 int now = 1; 35 int mp[1010][1010]; 36 37 inline bool check(int xx, int yy) 38 { 39 xx -= tab[1].x - 1, yy -= tab[1].y - 1; 40 for (register int i = 1 ; i <= now ; i ++) 41 { 42 int tx = xx + tab[i].x - 1, ty = yy + tab[i].y - 1; 43 if (tx <= 0 or tx > n or ty <= 0 or ty > m) return 0; 44 if (mp[tx][ty] == 0) return 0; 45 mp[tx][ty] = 0; 46 } 47 return 1; 48 } 49 50 int main() 51 { 52 q = read(); 53 while (q--) 54 { 55 n=read(), m=read(), x=read(), y=read(); 56 cnt = now = 1; 57 for (register int i = 1 ; i <= n ; i ++) 58 { 59 for (register int j = 1 ; j <= m ; j ++) 60 { 61 char ch; 62 cin >> ch; 63 if (ch == '.') mp[i][j] = 0; 64 else 65 { 66 mp[i][j] = 1; 67 a[cnt].x = i; 68 a[cnt++].y = j; 69 } 70 } 71 } 72 for (register int i = 1 ; i <= x ; i ++) 73 { 74 for (register int j = 1 ; j <= y ; j ++) 75 { 76 char ch; 77 cin >> ch; 78 if (ch == '.') continue; 79 else 80 { 81 tab[now].x = i; 82 tab[now++].y = j; 83 } 84 } 85 } 86 cnt--, now--; 87 for (register int i = 1 ; i <= cnt ; i ++) 88 { 89 if (mp[a[i].x][a[i].y] == 0) continue; 90 if (!check(a[i].x, a[i].y)) 91 { 92 puts("NIE"); 93 goto End; 94 } 95 } 96 97 puts("TAK"); 98 End:; 99 } 100 return 0; 101 }