1.4.4 密码锁
题目考查
暴力 容斥原理 环形距离
解题思路
首先我们比较容易的想出一个 O ( n 3 ) O(n^3) O(n3)的暴力方式, 枚举每一种情况, 分别判断是否合法即可. 对于通过本题是足够的.
但对于这题, 我们有一种更好的
O
(
1
)
O(1)
O(1)方式求解.
用容斥原理, 我们可以先计算出对于每一组密码合法的总情况数量, 然后再减去二者同时合法的情况.
其中某组密码合法的情况 = min(5, n) * min(5, n) * min(5, n)
.
假设 n ≥ 5 n \ge 5 n≥5, 考虑到对于两个密码而言, 如果当前位最小距离差为 d i s dis dis, 则会有 5 − d i s 5 - dis 5−dis种重复情况.
例如:
9
1 5 9
2 8 7那么两个密码第一位重复的数字有: 9, 1, 2, 3 共4种
两个密码第二位重复的数字有: 6, 7 共2种
两个密码第三位重复的数字有: 7, 8, 9 共3种因此总的重复情况为: 4 ∗ 2 ∗ 3 4 * 2 * 3 4∗2∗3种.
如果n < 5的情况, 那么实际上只有一组密码产生了贡献. 我们直接减去 n ∗ n ∗ n n * n * n n∗n∗n即可.
对于本题, 我们还需要会求两个数字的最小环形距离.
我们发现对于数字 x , y x, y x,y, 二者的距离无非是: ∣ x − y ∣ |x - y| ∣x−y∣ 和 n − ∣ x − y ∣ n - |x - y| n−∣x−y∣.
题目细节
无
AC代码
容斥原理: O ( 1 ) O(1) O(1)
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
int a[5], b[5];
int main()
{
int n; cin >> n;
rep(i, 3) cin >> a[i]; rep(i, 3) cin >> b[i];
int res = 2 * min(5, n) * min(5, n) * min(5, n);
if (n >= 5) {
int qaq = 1;
rep(i, 3) {
int dis = min(abs(a[i] - b[i]), n - abs(a[i] - b[i]));
qaq *= max(5 - dis, 0);
}
res -= qaq;
}
else res -= n * n * n;
cout << res << endl;
return 0;
}
暴力: O ( n 3 ) O(n^3) O(n3)
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
int n;
int a[5], b[5], c[5];
bool fact() {
bool flaga = 1, flagb = 1;
rep(i, 3) {
int disa = min(abs(c[i] - a[i]), n - abs(c[i] - a[i]));
int disb = min(abs(c[i] - b[i]), n - abs(c[i] - b[i]));
if (disa > 2) flaga = 0;
if (disb > 2) flagb = 0;
}
return flaga | flagb;
}
int main()
{
cin >> n;
rep(i, 3) cin >> a[i]; rep(i, 3) cin >> b[i];
int res = 0;
rep(i, n) rep(j, n) rep(k, n) {
c[1] = i, c[2] = j, c[3] = k;
res += fact();
}
cout << res << endl;
return 0;
}