hihocoder编程练习赛19

hihocoder编程练习赛19

A

题目要求

描述
小Hi的学校大礼堂的地毯是由很多块N × M大小的基本地毯拼接而成的。
由于大礼堂面积非常大,可以认为整片地毯是由基本地毯无限延伸拼接的。
现在给出K张地毯的照片,请你判断哪些照片可能是小Hi学校大礼堂地毯的一部分。不需要考虑旋转照片的方向。

输入
第1行包含三个整数,N,M 和 K。
第2~N+1行包含一个N × M的矩阵,代表基本地毯的样式。其中每一个元素都是一个大写字母(A-Z)。
之后是 K 张照片的数据。
每张照片的第一行包含两个整数,H 和 W,代表照片的大小。
以下 H 行包含一个 H × W的矩阵,代表照片中地毯的样式。其中每一个元素都是一个大写字母(A-Z)。
对于80%的数据,1 ≤ N, M ≤ 10, 1 ≤ H, W ≤ 100
对于100%的数据, 1 ≤ N, M ≤ 50, 1 ≤ K ≤ 10, 1 ≤ H ≤ 100, 1 ≤ W ≤ 800。

输出
对于每张照片,输出YES或者NO代表它是否可能是大礼堂地毯的一部分。

样例输入
2 3 3
ABC
ABD
3 3
BCA
BDA
BCA
2 3
BAC
BAD
7 14
ABCABCABCABCAB
ABDABDABDABDAB
ABCABCABCABCAB
ABDABDABDABDAB
ABCABCABCABCAB
ABDABDABDABDAB
ABCABCABCABCAB

样例输出
YES
NO
YES

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <bits/stdc++.h>
#define mem(a, b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 10000 + 50;
int n, m , k;
char a[55][55];
char g[120][850];
char t[120][850];
int c, r;
bool check(int gi, int gj){
if(gi + r > 120) return false;
if(gj + c > 850) return false;
int p,q,i,j;
for(i = gi,p=0; p < r; p++,i++)
for(j = gj,q=0; q < c; q++,j++)
if(g[i][j] != t[p][q]) return false;
return true;
}
int main(){
//freopen("input.txt", "r", stdin);
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m >> k;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
cin >> a[i][j];
for(int i = 0; i < 120; i++)
for(int j = 0; j < 850; j++){
g[i][j] = a[i%n][j%m];
}
for(int i = 0; i < k; i++){
cin >> r >> c;
for(int i = 0; i < r; i++)
for(int j = 0; j < c; j++)
cin >> t[i][j];
bool fg = false;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(t[0][0] == g[i][j])
if(check(i,j)){
fg = true;
break;
}
}
if(fg){
break;
}
}
if(fg) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}

思路

把原地摊扩充
在n*m中枚举每个起点后判断是否相同

B

题目要求

描述
给定一个{1..N}的排列A1, A2, … AN,每一次操作可以将相邻的两个数一起移动(保持两个数相邻且前后顺序不变)到任意位置。询问至少经过多少次操作,可以使得原序列变为1, 2, …, N。
例如对于54321,把32一起移动到最左端得到32541;再把25一起移动到最右端得到34125;再把12一起移动到最左端得到12345。

输入
第1行:1个正整数 T,表示输入数据的组数
第2..T+1行:每行一个字符串,表示初始排列
对于30%的数据:T = 1, 1 ≤ N ≤ 5
对于100%的数据:1 ≤ T ≤ 5, 1 ≤ N ≤ 8

输出
第1..T行:每行一个整数,第i行表示第i个排列变化为1, 2, …, N所需要的最少步数。若无可行方案,输出”-1”。

样例输入
2
54321
321

样例输出
3
-1

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<bits/stdc++.h>
using namespace std;
int temp[10];
void run(){
queue<int> q;
map<int,int> step;
int s;
cin>>s;
q.push(s);
step[s] = 0;
int len=0;
while(!q.empty()){
int t = q.front();
int now = step[t];
q.pop();
len = 0;
while( t>0 ){
temp[len++] = t%10;
t/=10;
}
int a, b[8];
for(int i=0; i<len-1; i++){
int cnt=0;
a = temp[i] + temp[i+1]*10;
for(int j=0; j<len; j++){
if( j==i || j==i+1 ) continue;
b[cnt++] = temp[j];
}
for(int pos=0; pos<=cnt; pos++){
int next = 0;
for(int j=cnt; j>=0; j--){
if( j<cnt ) next = next*10 + b[j];
if (pos==j) next = next*100 + a;
}
if( !step.count(next) ){
q.push(next);
step[next] = now+1;
}
}
}
}
int t=0;
for(int i=1; i<=len; i++){
t = t*10 + i;
}
if (!step.count(t)) step[t] = -1;
cout<<step[t]<<endl;
}
int main(){
int T;
cin>>T;
while(T--) run();
return 0;
}

思路

bfs暴力枚举
每一个状态看成一个数字利用map映射到移动步骤中
判重用map里的count

D

题目要求

描述
H国有 n 个城市,编号1..n。城市间有n-1条铁路,保证任意两个城市可以通过铁路互达,且路线唯一。
现有 m 次询问,每次询问两条铁路线是否相交(有共同经过的城市或铁路)。

输入
第一行一个数 T,表示数据组数
对于每一组数据:
第一行两个数n, m
第2~n行,每行两个数x, y表示有一条铁路连接城市 x 和 y
接下来m行每行四个数,x1, y1, x2, y2 表示询问城市 x1 和 y1 之间的路线是否和城市 x2 和 y2 之间的路线相交。
对于40%的数据,1 ≤ n, m ≤ 100
对于60%的数据,1 ≤ n, m ≤ 1000
对于100%的数据,1 ≤ T ≤ 10, 1 ≤ n, m ≤ 100000 1 ≤ x, y, x1, y1, x2, y2 ≤ n

输出
对于每次询问输出YES或NO

样例输入
1
4 2
1 2
2 3
3 4
1 2 3 4
1 4 2 3

样例输出
NO
YES

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include<bits/stdc++.h>
#define maxn 100050
#define inf 0x3f3f3f3f
#define LL long long
#define pb push_back
#define pii pair<int,int>
#define fi first
#define se second
#define mm(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const double eps = 1e-6;
const LL mod=1e9+7;
const LL INF=(LL)1e18;
using namespace std;
LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
LL qpow(LL x,LL y){LL re=1,base=x%mod;while(y){if(y&1)re=(re*base)%mod;base=(base*base)%mod;y>>=1;}return re;}
int deep[maxn],f[maxn],anc[maxn][25];
vector<int>e[maxn];
void dfs(int x,int fa){
anc[x][0]=f[x];
for(int i=1;i<=20;i++) anc[x][i]=anc[anc[x][i-1]][i-1];
for(int i=0;i<e[x].size();i++){
int next=e[x][i];
if(next!=fa){
f[next]=x;
deep[next]=deep[x]+1;
dfs(next,x);
}
}
}
int lca(int x,int y){
if(deep[x]<deep[y]) swap(x,y);
for(int i=20;i>=0;i--) if(deep[anc[x][i]]>=deep[y]) x=anc[x][i];
if(x==y) return x;
for(int i=20;i>=0;i--) if(anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i];
return f[x];
}
bool check(){
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
int t1=lca(x1,y1);
int t2=lca(x2,y2);
if(lca(t1,t2)==t1){
if(lca(t2,x1)==t2 || lca(t2,y1)==t2) return true;
}
if(lca(t1,t2)==t2){
if(lca(t1,x2)==t1 || lca(t1,y2)==t1) return true;
}
return false;
}
int main(){
// freopen("input.txt","r",stdin);
// freopen("ouput.txt","w",sdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int t;
cin>>t;
while(t--){
int n,m;
cin>>n>>m;
for(int i=0;i<=n;i++) e[i].clear();
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
e[u].pb(v);
e[v].pb(u);
}
mm(f,0);
mm(anc,0);
mm(deep,0);
deep[1]=1;
dfs(1,0);
for(int i=1;i<=m;i++){
if(check()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}

思路

x1和y1的lca为t1
x2和y2的lca为t2
若相交 t1或t2必为交点
若t1是交点 那么x1或y1的至少一个和t2的lca为t2
若t2是交点 那么x2或y2的至少一个和t1的lca为t1

文章目录
  1. 1. hihocoder编程练习赛19
    1. 1.1. A
      1. 1.1.1. 题目要求
      2. 1.1.2. 参考AC代码
      3. 1.1.3. 思路
    2. 1.2. B
      1. 1.2.1. 题目要求
      2. 1.2.2. 参考AC代码
      3. 1.2.3. 思路
    3. 1.3. D
      1. 1.3.1. 题目要求
      2. 1.3.2. 参考AC代码
      3. 1.3.3. 思路
|