这次 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++。
标签:P9752,错误,int,题解,return,密码,dist,密码锁,define From: https://www.cnblogs.com/WaterSun/p/P9752.html