[题解]P9752 [CSP-S 2023] 密码锁

发布时间 2023-10-22 22:35:38作者: WaterSun_FireRain

这次 CCF 的行为过于迷惑了。

思路

首先发现只会有 \(10^5\) 种密码,考虑枚举它们,然后去 check

假设当前密码是:\(p_1,p_2,p_3,p_4,p_5\)。如果它能从对于所有 \(1 \sim n\) 种错误的密码按照题目所述的操作得到,那么此密码就是合法的。

假设我们现在判断当前密码能否由第 \(i\) 种错误密码得到。

不难发现如果错误的位数为 \(0\) 或者大于 \(2\),此密码一定不合法。因为如果为 \(0\),表示这是错误的密码;如果大于 \(2\),表示不能通过一次操作得到。

如果错误的位数为 \(1\) 一定合法,因为我们可以只转动错误的一位来得到。

错误位数为 \(2\) 的情况,我们需要考虑错误的两位是否相邻,如果不相邻一定不行。

其次判断这两个错误的位置能否通过转动相同幅度得到。这里我是用了一个 \(dist(i,j)\) 来计算从 \(i\)\(j\) 需要转动几次,当然这里需要计算往上转和往下转两种情况。

code

#include <bits/stdc++.h>
#define fst first
#define snd second
#define re register
#define int long long

using namespace std;

typedef pair<int,int> pii;
const int N = 25;
int n,ans;
int p[N];
int t[N] = {0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9};//破环成链,便于计算 dist 
int arr[N][N];

inline int read(){
    int r = 0,w = 1;
    char c = getchar();
    while (c < '0' || c > '9'){
        if (c == '-') w = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9'){
        r = (r << 1) + (r << 3) + (c ^ 48);
        c = getchar();
    }
    return r * w;
}

inline pii dist(int x,int y){
    pii res;
    for (re int i = x;t[i] != y;i++) res.fst++;
    for (re int i = 10 + x;t[i] != y;i--) res.snd++;
    return res;
}

inline bool check(int x){
    vector<int> v;
    for (re int i = 1;i <= 5;i++){
        if (p[i] != arr[x][i]) v.push_back(i);
    }
    int sz = v.size();
    if (!sz || sz > 2) return false;
    if (sz == 1) return true;
    if (v[1] - v[0] == 1){
        pii a = dist(p[v[0]],arr[x][v[0]]);
        pii b = dist(p[v[1]],arr[x][v[1]]);
        if (a.fst == b.fst || a.snd == b.snd) return true;
    }
    return false;
}

inline void dfs(int u){
    if (u == 6){
        for (re int i = 1;i <= n;i++){
            if (!check(i)) return;
        }
        ans++;
        return;
    }
    for (re int i = 0;i <= 9;i++){
        p[u] = i;
        dfs(u + 1);
    }
}

signed main(){
    n = read();
    for (re int i = 1;i <= n;i++){
        for (re int j = 1;j <= 5;j++) arr[i][j] = read();
    }
    dfs(1);
    printf("%lld",ans);
    return 0;
}

最后

不要脸的放上我的游记

尽管没发挥好,但是来年再战。

CSP-2024 S RP++。