P9752 [CSP-S 2023] 密码锁题解
1.题意:
从正确密码开始,随机转动密码锁一次,每次可以:
-
转动一个拨圈(数字可以增加或减少)
-
同时转动两个相邻的拨圈(两个拨圈变化幅度相同)
现在给出了n个锁车后的状态(都不是正确密码),需要计算有多少种可能的正确密码,使得每个正确密码都能通过上述操作产生所有给定的n个状态。
2.思路:
-
对于每个可能的正确密码,我们需要验证它是否能通过单次操作(单拨圈或双相邻拨圈转动)生成所有给定的n个状态。
-
五位密码共有10^5=100,000种可能,可以全部枚举。
-
对于每密码,检查:
-
对于每个给定的状态,至少存在一种操作(单拨圈或双相邻拨圈转动)能从密码得到该状态
-
密码不能与任何给定状态相同(题目说明)
-
-
统计满足上述所有条件的密码数量。
3.示例解释
对于样例输入1:
1
0 0 1 1 5
可能的正确密码有81种:
-
45种通过单拨圈转动得到"00115"(每个位置可以±1,共5个位置×9种变化=45)
-
36种通过双相邻拨圈转动得到"00115"(4对相邻位置×9种变化=36)
36+45=81
因此输出81。
4.AC代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[10][10];
int p[10];
int main(){
int n,ans=0;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=5;j++){
cin>>a[i][j];
}
}
for(p[1]=0;p[1]<=9;p[1]++){
for(p[2]=0;p[2]<=9;p[2]++){
for(p[3]=0;p[3]<=9;p[3]++){
for(p[4]=0;p[4]<=9;p[4]++){
for(p[5]=0;p[5]<=9;p[5]++){
bool flag=0;
for(int i=1;i<=n;i++){
int cnt=0;
for(int j=1;j<=5;j++){
if(a[i][j]!=p[j]){
cnt++;
}
}
if(cnt>=3 || cnt==0){
flag=1;
break;
}
if(cnt==1) continue;
for(int j=1;j<=5;j++){
if(a[i][j]!=p[j]){
if(a[i][j+1]==p[j+1]){
flag=1;
break;
}
if((a[i][j]+10-p[j])%10==(a[i][j+1]+10-p[j+1])%10){
break;
}
else {
flag=1;
break;
}
}
}
if(flag==1) break;
}
if(flag==0) ans++;
}
}
}
}
}
cout<<ans;
return 0;
}