洛谷P9752 [CSP-S 2023] 密码锁

P9752 [CSP-S 2023] 密码锁

题目描述

小 Y 有一把五个拨圈的密码锁。如图所示,每个拨圈上是从 \(0\)\(9\) 的数字。每个拨圈都是从 \(0\)\(9\) 的循环,即 \(9\) 拨动一个位置后可以变成 \(0\)\(8\)

因为校园里比较安全,小 Y 采用的锁车方式是:从正确密码开始,随机转动密码锁仅一次;每次都是以某个幅度仅转动一个拨圈或者同时转动两个相邻的拨圈。

当小 Y 选择同时转动两个相邻拨圈时,两个拨圈转动的幅度相同,即小 Y 可以将密码锁从 \(\tt{0\;0\;1\;1\;5}\) 转成 \(\tt{1\;1\;1\;1\;5}\),但不会转成 \(\tt{1\;2\;1\;1\;5}\)

时间久了,小 Y 也担心这么锁车的安全性,所以小 Y 记下了自己锁车后密码锁的 \(n\) 个状态,注意这 \(n\) 个状态都不是正确密码。

为了检验这么锁车的安全性,小 Y 有多少种可能的正确密码,使得每个正确密码都能够按照他所采用的锁车方式产生锁车后密码锁的全部 \(n\) 个状态。

输入格式

输入的第一行包含一个正整数 \(n\),表示锁车后密码锁的状态数。

接下来 \(n\) 行每行包含五个整数,表示一个密码锁的状态。

输出格式

输出一行包含一个整数,表示密码锁的这 \(n\) 个状态按照给定的锁车方式能对应多少种正确密码。

输入输出样例 #1

输入 #1

1
0 0 1 1 5

输出 #1

81

说明/提示

【样例 1 解释】

一共有 \(81\) 种可能的方案。

其中转动一个拨圈的方案有 \(45\) 种,转动两个拨圈的方案有 \(36\) 种。

【样例 2】

见选手目录下的 lock/lock2.in 与 lock/lock2.ans。

【数据范围】

对于所有测试数据有:\(1 \leq n \leq 8\)

测试点 \(n\leq\) 特殊性质
\(1\sim 3\) \(1\)
\(4\sim 5\) \(2\)
\(6\sim 8\) \(8\) A
\(9\sim 10\) \(8\)

特殊性质 A:保证所有正确密码都可以通过仅转动一个拨圈得到测试数据给出的 \(n\) 个状态。

思路

看到n最大才8你不暴力枚举你等啥呢!!!

ACcode:

#include<bits/stdc++.h>
#define f(x,l,r) for(int x=l;x<=r;x++) //这里将枚举时长长的for语句简写
typedef long long ll;
using namespace std;
const int N=10;
int n,ans;
int a[N][6],True[6],aim[6]; //a:n个状态,每个状态的数组下标从1开始
/*
1.11111~99999:81种可能
2.只转一次
3.一次1~2个
4.n个状态
check:检查某个正确密码是否可以只转动一次达到目标状态
True[1~5]:正确密码
aim[1~5]:目标状态
*/
bool check(int True[6],int aim[6]){
	int c[6],cnt=0;
	//表示第i个位置需要转动的幅度,cnt记录有多少个不同的位置需要转动
	for(int i=1;i<=5;i++){ //遍历5个数字
		c[i]=(True[i]-aim[i]+10)%10; //+10%10是用来处理9的下一个是0这一情况
		if(c[i]!=0) cnt++; //c[i]!=0说明有差异,这个位置需要转动
	}
	//1.所有位置都与正确密码相同(显然不可能,但还是写一下,理解思路用。后文"相同/不同"都代指与正确密码的差异
	if(cnt==0) return 0;
	//2.只有一个位置不同,只转动了一个圈,可行
	if(cnt==1) return 1;
	//3.有两个位置不同,检查是否转动相邻圈
	if(cnt==2){
		//枚举(x,x+1)位置,x∈[1,4]
		for(int x=1;x<5;x++){
			//检查x和x+1是否都不同,且转动幅度要相同
			if(c[x]!=0 and c[x+1]!=0 and c[x]==c[x+1]){
				//还要检查其他位置是否没变化
				bool flag=1;
				for(int y=1;y<=5;y++){
					//跳过这两个位置检查其他位置
					if(y!=x and y!=x+1 and c[y]!=0){
						//c[y]!=0说明其他位置变化了,不符合
						flag=0;
						break;
					}
				}
				if(flag) return 1; //只有一对相邻的位置变化,符合要求
			}
		}
	}
	//4.其他情况:全部不合法
	return 0;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>a[i][1]>>a[i][2]>>a[i][3]>>a[i][4]>>a[i][5];
	f(p1,0,9){
		True[1]=p1;
		f(p2,0,9){
			True[2]=p2;
			f(p3,0,9){
				True[3]=p3;
				f(p4,0,9){
					True[4]=p4;
					f(p5,0,9){
						True[5]=p5;
						//疯狂枚举密码并检查能否产生n个状态
						bool is=1;
						for(int i=1;i<=n;i++){
							//如果存在一个状态无法由此密码得到,跳过
							if(!check(True,a[i])){
								is=0;
								break;
							}
						}
						//如果全部都可以得到
						if(is) ans++;
					}
				}
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}
posted @ 2026-08-20 16:53  AAA_jiancaipifa  阅读(1)  评论(0)    收藏  举报