[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\) 种。

【数据范围】

对于所有测试数据有:\(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等于1的时候,答案肯定是81,但是当n比较大的时候,不知道该怎么做了?一直在想,他有什么样的性质才能这样?

但是,我一直有个感觉,这个题可以搜索,为什么呢?因为最多有5位密码,后来换了思路,我们搜索得到所有可能的状态,依次判断这种状态是否能通过拨圈达到题目中说的状态,这样的时间复杂度是O(100000),判断的时间复杂度为5n,所以最终的时间复杂是O(500000n)。

枚举的代码非常好写,但是判断的代码不好写,譬如。5 9会变成6 0,7 1,8 2,9 3,0 4,1 5,2 6,3 7,4 8共9种状态,我们发现他们的差是一样的,但是有个问题,9会变0,这个怎么处理?我最终的处理方法是判断两者之间的大小关系,如果发生变化,把小的数字加上10,从而保持原来的大小关系,代码如下:
点击查看代码

#include <bits/stdc++.h>
using namespace std;
int n,a[15][15],ans;
int c[10];
bool check(){
    for(int i=1;i<=n;i++){
        bool b=true;//是否转动过拨圈
        int f;
        for(int j=1;j<=5;j++){
            if(c[j]==a[i][j]) continue;
            else{
                if(b==false)
                    return false;
                if(c[j+1]!=a[i][j+1]&&j<=4){
                    if(c[j]<c[j+1]){
                        f=a[i][j+1];
                        if(a[i][j+1]<a[i][j]) f=a[i][j+1]+10;
                        if(f-a[i][j]!=c[j+1]-c[j]) return false;
                        j++;
                        b=false;
                        continue;
                    }
                    if(c[j+1]==c[j]){
                        if(a[i][j+1]!=a[i][j]) return false;
                        j++;
                        b=false;
                        continue;
                    }
                    if(c[j+1]<c[j]){
                        f=a[i][j];
                        if(a[i][j]<a[i][j+1]) f=a[i][j]+10;
                        if(f-a[i][j+1]!=c[j]-c[j+1]) return false;
                        j++;
                        b=false;
                        continue;
                    }
                }
                if((c[j+1]==a[i][j+1]&&j<=4)||j==5){
                    b=false;//已经转动过一次拨圈
                }
            }
        }
        if(b==true) return false;
    }
    return true;
}

void dfs(int k){
    if(k==6){
        if(check()) {
            ans++;
            //for(int i=1;i<=5;i++) cout<<c[i]<<" ";
            //cout<<endl;
        }
        return;
    }
    for(int i=0;i<=9;i++){
        c[k]=i;
        dfs(k+1);
        c[k]=0;
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=5;j++){
            scanf("%d",&a[i][j]);
        }
    }
    dfs(1);
    cout<<ans<<endl;
    return 0;
}
相关推荐
凉风听雪12 天前
VsCode插件:前端每日一题
前端·ide·vscode·每日一题
vortex513 天前
Shodan 进阶使用技巧:无高级会员如何搜索指定漏洞并进行批量验证
网络·安全·搜索引擎·网络安全·命令·搜索
C_GUIQU18 天前
【每日一题】24.10.14 - 24.10.20
每日一题
点亮~黑夜20 天前
【OD】【E卷】【真题】【100分】光伏场地建设规划(Python&Java&javaScript&C++&C)
java·c语言·javascript·c++·python·华为od·真题
wengad1 个月前
MindSearch CPU-only 版部署
人工智能·搜索
Damon小智1 个月前
【中级通信工程师】终端与业务(七):市场调查与研究
真题·复习资料·通信考试·中级通信工程师·终端与业务
Damon小智1 个月前
【中级通信工程师】终端与业务(二):终端产品
真题·复习资料·通信考试·中级通信工程师·终端与业务
sweetheart7-72 个月前
LeetCode54. 螺旋矩阵(2024秋季每日一题 21)
线性代数·矩阵·力扣·数组·每日一题
cyt涛2 个月前
搜索功能技术方案
mysql·elasticsearch·全文检索·canal·索引·数据同步·搜索
sweetheart7-72 个月前
LeetCode152. 乘积最大子数组(2024秋季每日一题 2)
数据结构·算法·动态规划·dp·每日一题