1 条题解

  • 0
    @ 2026-10-31 17:57:34

    思路

    题意简述:多组数据,每组给出一串 1~9 组成的数字,判断它是否是合法的安卓图案解锁轨迹。规则有两条:

    1. 每个点最多使用一次;
    2. 从点 AA 滑到点 BB 时,如果两点连线的中点恰好是九宫格中的另一个点 CC(三点共线且 CC 是线段中点),那么 CC 必须在此前已经被使用过,否则这一步非法。

    做法就是直接模拟:

    1. 先把编号 1∼91\sim9 映射到九宫格坐标:编号 vv 对应行 (v−1)/3+1(v-1)/3+1、列 (v−1) mod 3+1(v-1)\bmod3+1。
    2. 用 vis[1..9] 记录每个点是否已经走过,并把第一个点标记为已用。
    3. 依次检查相邻的两个点 A,BA,B:
      • 若 BB 已经走过,违反“每个点最多一次”,输出 NO;
      • 判断中点是否为格点:当且仅当两点的行坐标之和与列坐标之和都为偶数时,平均值才是整数,即中点落在九宫格内。此时算出中点编号,若它尚未被使用,则这一步跨过了未使用的点,输出 NO;
      • 通过检查后,把 BB 标记为已使用。
    4. 全部相邻步都合法则输出 YES。

    正确性:模拟逐条覆盖了两条规则。重复使用点会在 vis[a[i]] 处被抓到;只有两坐标和均为偶数时才存在整数中点,而 1∼31\sim3 范围内两个格点的平均仍在九宫格内,所以此时“中点编号未使用就该判非法”与规则完全一致;其它情况(如斜向相邻、行或列差为奇数等)没有中间格点,不构成“跨点”,允许直接连接。

    复杂度:每组数据只扫描一遍字符串,时间 O(L)O(L),其中 LL 为密码长度;空间 O(1)O(1)(坐标表、访问数组大小固定为 10)。由于只有 9 个点,长度超过 9 的串必然重复,会被判为 NO。

    代码

    #include<bits/stdc++.h>
    #define int long long
    #define dd double
    #define str string
    #define el cout << endl
    #define re return
    #define ff first
    #define ss second
    #define pll pair<int,int>
    #define pdd pair<dd,dd>
    #define all(x) x.begin(),x.end()
    #define pb push_back
    #define sz(x) (int) x.size()
    using namespace std;
    
    // 判断一串数字是否为合法的安卓图案解锁轨迹
    void go(str s){
        vector<int>a;
        // vis[v] 表示编号 v 的点是否已经被使用
        vector<int>vis(10,0);
        // coor[v] 保存编号 v 在 3x3 九宫格中的坐标
        vector<pll>coor(10,{0,0});
        for(int i=1;i<=3;i++){
            for(int j=1;j<=3;j++){
                coor[(i-1)*3+j] = {i,j};
            }
        }
        // 把字符密码转换成数字序列
        for(char i:s){a.pb(i-'0');}
    
        // 第一个点直接标记为已使用
        vis[a[0]] = 1;
        for(int i=1;i<a.size();i++){
            int lx = coor[a[i-1]].ff, ly = coor[a[i-1]].ss;
            int nx = coor[a[i]].ff, ny = coor[a[i]].ss;
    
            // 目标点之前已经走过,违反“每个点最多使用一次”
            if(vis[a[i]]){
                cout<<"NO";el;re;
            }
    
            // 行列坐标和都为偶数时,中点才是九宫格内的整数格点
            if((lx+nx)%2==0 and (ly+ny)%2==0){
                int mx = (lx+nx)/2;
                int my = (ly+ny)/2;
                int num = (mx-1)*3 + my;
                // 跨过的中点必须已经被使用
                if(!vis[num]){
                    cout<<"NO";el;re;
                }
            }
            vis[a[i]] = 1;
        }
    
        // 所有相邻步都合法
        cout<<"YES";el;
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);cout.tie(nullptr);
        int t=1;
        // 本题为多组数据,一直读到文件结束,不需要预先读取组数
        str s;
        while(cin>>s){
            go(s);
        }
        return 0;
    }
    
    • 1

    信息

    ID
    53
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者