hihoCoder 编程练习赛19 A, B

题目1 : 大礼堂地毯

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

小Hi的学校大礼堂的地毯是由很多块N × M大小的基本地毯拼接而成的。例如由2×3的基本地毯

ABC
ABD

拼接而成的大礼堂整片地毯如下:

       ...       
  ABCABCABCABCAB
  ABDABDABDABDAB
. ABCABCABCABCAB .
. ABDABDABDABDAB .
. ABCABCABCABCAB .
  ABDABDABDABDAB
  ABCABCABCABCAB
       ...

由于大礼堂面积非常大,可以认为整片地毯是由基本地毯无限延伸拼接的。  

现在给出K张地毯的照片,请你判断哪些照片可能是小Hi学校大礼堂地毯的一部分。不需要考虑旋转照片的方向。

例如

BCA
BDA
BCA

可能是上述地毯的一部分,但

BAC
BAD

不可能是上述地毯的一部分。

输入

第1行包含三个整数,NM 和 K。  

第2~N+1行包含一个N × M的矩阵,代表基本地毯的样式。其中每一个元素都是一个大写字母(A-Z)。  

之后是 K 张照片的数据。  

每张照片的第一行包含两个整数,H 和 W,代表照片的大小。  

以下 H 行包含一个 H × W的矩阵,代表照片中地毯的样式。其中每一个元素都是一个大写字母(A-Z)。

对于80%的数据,1 ≤ NM ≤ 10, 1 ≤ HW ≤ 100  

对于100%的数据, 1 ≤ NM ≤ 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

解析:判断是不是由基本地毯组成的,只需要将基本地毯扩大的足够大,然后用滚动数组判断即可

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1000009;

char tp[59][59], mp[1009][1009], s[1009][1009];
int n, m, w, h;

bool judge()
{
     for(int i = 0; i < m; i++) strcpy(s[i], tp[i]);
     int num = n;
     while(num <= w)
     {
         for(int i = 0; i < m; i++)
            strcat(s[i], tp[i]);
         num += n;
     }
     int k = 0;
     for(k = 0; k < m; k++) if(strstr(s[k], mp[0])) break;
     if(k >= m) return false;
     k = (k + 1) % m;
     for(int i = 1; i < h; i++)
     {
         if(strstr(s[k], mp[i])) k = (k + 1) % m;
         else return false;
     }
     return true;
}


int main()
{
    int k;
    scanf("%d%d%d", &m, &n, &k);

    for(int i = 0; i < m; i++)
    {
        scanf(" %s", tp[i]);
    }
    while(k--)
    {
        scanf("%d%d", &h, &w);
        for(int i = 0; i < h; i++)
        {
            scanf(" %s", mp[i]);
        }
        if(judge()) puts("YES");
        else puts("NO");
    }
    return 0;
}



//2 3 3
//ABC
//ABD
//7 14
//ABCABCABCABCAB
//ABDABDABDABDAB
//ABCABCABCABCAB
//ABDABDABDABDAB
//ABCABCABCABCAB
//ABDABDABDABDAB
//ABCABCABCABCAB
//NO


题目2 : 数组重排3

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

给定一个{1..N}的排列A1A2, ... 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

解析:BFS去搜索,用队列去枚举所有情况,map标记,遇到第一个有序的,返回次数即可

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 1000009;
typedef pair<int, int> P;


int solv(char str[])
{
    int d[11], len = strlen(str);
    queue<P> q;
    map<int, int> mp;
    mp.clear();
    int s, e; s = e = 0;
    for(int i = 0; str[i]; i++) s = s * 10 + str[i] - '0', e = e * 10 + i + 1;
    mp[s] = 1;
    q.push(make_pair(s, 0));
    while(!q.empty())
    {
        P p = q.front(); q.pop();
        s = p.first;
        if(s == e) return p.second;
        for(int i = 0; i < len; i++) d[i] = s % 10, s /= 10;
        for(int i = 0, j = len - 1; i < j; i++, j--) swap(d[i], d[j]);
        int cur = 0;
        for(int i = 0; i < len - 1; i++)
        {
            for(int j = 0; j < len - 1; j++)
            {
                cur = 0;
                if(j + 1 == len - 1)
                {
                    for(int k = 0; k < len; k++)
                    {
                        if(k == i || k == i + 1) continue;
                        cur = cur * 10 + d[k];
                    }
                    cur = cur * 100 + d[i] * 10 + d[i+1];
                }
                else
                {
                    for(int k = 0; k < j; k++)
                    {
                        if(k == i || k == i + 1) continue;
                        cur = cur * 10 + d[k];
                    }
                    cur = cur * 100 + d[i] * 10 + d[i+1];
                    for(int k = j; k < len; k++)
                    {
                        if(k == i || k == i + 1) continue;
                        cur = cur * 10 + d[k];
                    }
                }
                if(mp[cur]) continue;
                mp[cur] = 1;
                q.push(make_pair(cur, p.second+1));
            }
        }
    }
    return -1;
}

int main()
{
    int t;
    char str[11];
    scanf("%d", &t);
    while(t--)
    {
        scanf(" %s", str);
        printf("%d\n", solv(str));
    }
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值