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
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
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
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