密码锁

189 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情

题目描述

农夫约翰的奶牛们总是偷偷的逃出他的农场,去外面为非作歹。

农夫约翰为了防止它们私自逃离农场,购买了一个密码锁,以此阻止奶牛们打开农场大门。

约翰知道他的奶牛们都非常聪明,因此他想要确保它们不能通过简单的尝试一些密码组合,就轻易的将锁打开。

锁具上有三个密码拨盘,每个拨盘上的数字为 1…N1…N,其中 11 和 NN 相邻(因为拨盘是圆形的)。

一共有两种可以打开密码锁的数字组合,一组是约翰设置的密码组合,一组是制造商设置的密码组合。

这种锁具有一定的容错性,只要三个表盘上的数字与任意一组正确密码组合的对应位置数字相距两个位置以内,锁均会打开。

例如,假设约翰设置的密码组合是 (1,2,3)(1,2,3),制造商设置的密码组合是 (4,5,6)(4,5,6)。

此时我们输入组合 (1,3,5)(1,3,5) 就可以将锁打开,因为这与约翰设置的密码接近,输入组合 (2,4,8)(2,4,8) 也可以将锁打开,因为这与制造商设置的密码接近。

但是,如果我们输入组合 (1,5,6)(1,5,6) 就不能将锁打开,因为它和两个密码都不接近。

现在给定你两个设置好的密码,请你判断一共有多少种密码组合可以将锁打开。

注意,密码组合是有序的,因此 (1,2,3)(1,2,3) 和 (3,2,1)(3,2,1) 是两种不同的组合。

输入格式

第一行包含整数 NN。

第二行包含三个整数,表示约翰设置的密码组合。

第三行包含三个整数,表示制造商设置的密码组合。

输出格式

输出一个整数,表示可以打开锁的密码组合数量。

数据范围

1≤N≤1001≤N≤100

输入样例:

50
1 2 3
5 6 7

输出样例:

249

思路

暴力解法

由于数据集较小,可以采用暴力枚举的方法。枚举每一种密码出现的情况,只要这个密码在圆环上满足和a密码或者b密码的距离小于2,就可以在结果上加1,最后输出答案即可。

算两点在圆环上的距离

image-20220604195102575

优化解法

答案 = 所有可能出现的情况数(a密码产生的数量+b密码产生的数量)- 两种密码产生的公共的数量;

所有可能出现的情况:min(n, 5) * min(n, 5) * min(n, 5)

两种密码的交集:

同时距a0和bo小于2的点数,满足一下规律,(点数和a0、b0的距离相关)

规律

image-20220604202707114

代码

#include <iostream>
​
using namespace std;
​
int n;
int a[3], b[3];
​
​
int both()
{
    if(n <= 5) return n * n * n;
    int res = 1;
    for(int i = 0;i < 3;i ++)
    {
        int d = abs(a[i] - b[i]);
        res *= max(0, 5 - d) + max(0, 5 - (n - d));
    }
    
}
​
int ans()
{
    int res = 1;
    for(int i = 0;i < 3;i ++)
    {
        res *= min(n, 5);
    }
    return res;
}
​
int main()
{
    
    
    cin >> n;
    for(int i = 0;i < 3;i ++) cin >> a[i];
    for(int i = 0;i < 3;i ++) cin >> b[i];
    cout << ans() * 2 - both() << endl;
    return 0;
}