因为只有std,没有自我实现,所以是无码专区
problem
给定一个 q q q 进制的乘法表,每个字符代表着 0 ∼ p − 1 0\sim p-1 0∼p−1 不同的数字。
求每个字符代表的数字。保证有解。
× \times × | A | B | C | D |
---|---|---|---|---|
A | CD | BB | DC | BA |
B | BB | BB | BB | BB |
C | DC | BB | DB | BC |
D | BA | BB | BC | BD |
i.e.
CD
\text{CD}
CD 表示的是
p
p
p 进制下的结果,即:
A
×
A
=
C
⋅
p
+
D
A\times A=C·p+D
A×A=C⋅p+D。
上述例子的答案为: A=3,B=0,C=2,D=1 \text{A=3,B=0,C=2,D=1} A=3,B=0,C=2,D=1。
时限: 10 s 256 M B 10s\ 256MB 10s 256MB
我的想法
表示 0 0 0 的字符非常好找:所在“十字架”结构全都是该字符。
表示 1 1 1 的字符也很好找:所在“十字架”结构高位全是 0 0 0 字符,其余字符在低位出现的次数相同。
- 对于
q≤50
的 50 % 50\% 50% 部分
显然,所有代表数字 < q <\sqrt{q} <q 的字符,自乘后高位一定是 0 0 0 对应字符,低位字符一定表示一个平方数。
找出所有 < q <\sqrt{q} <q 的字符,全排列枚举每个字符对应的数字,然后搜索乘法表是否冲突。
时间复杂度 O ( q ! q 2 ) O(\sqrt{q}!q^2) O(q!q2)。
- 对于
q≤2000
的 100 % 100\% 100% 部分
很容易知道在 p p p 进制下,有哪些 ≥ q \ge \sqrt{q} ≥q 的数字平方高位是相同的,即某数字代表字符在高位出现次数是易得的。
如果某些数字出现高位的次数相同,就全排列匹配搜索,否则唯一就可以确定字符和数字的匹配。
时间复杂度未知——只是认为这样可以。
solution
0 0 0 对应字符很好找。
然后对于 1 ∼ q − 1 1\sim q-1 1∼q−1 的每个元素 i i i,其在乘法表中,对应的十位一定是 0 ∼ i − 1 0\sim i-1 0∼i−1,一共是出现了 i i i 个不同的数字。
直接统计十位的个数,然后匹配即可。
时间复杂度 O ( n 2 ) O(n^2) O(n2)。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#define N 4005
#define M 15
#define mod 1000000007
#define mod2 100000000
#define ll long long
#define maxi(a,b) (a)>(b)? (a) : (b)
#define mini(a,b) (a)<(b)? (a) : (b)
using namespace std;
int cnt;
int p;
int i, j;
int a[N][N];
int c[N][N];
int cc[N];
int ans[N], pp[N];
int main() {
freopen("multiplication.in", "r", stdin);
freopen("multiplication.out", "w", stdout);
cnt = 1;
scanf("%d", &p);
for (i = 0; i < p; i++) {
for (j = 1; j <= p; j++) {
scanf("%d", &a[i][2 * j - 1]);
cc[ a[i][2 * j - 1] ]++;
scanf("%d", &a[i][2 * j]);
cc[ a[i][2 * j] ]++;
}
}
int ma = cc[0];
int index = 0;
for (i = 0; i < p; i++) {
if (cc[i] > ma) {
ma = cc[i];
index = i;
}
}
ans[0] = index;
memset(cc, 0, sizeof(cc));
for (i = 0; i < p; i++) {
for (j = 1; j <= p; j++) {
if (c[i][ a[i][2 * j - 1] ] == 0) {
c[i][ a[i][2 * j - 1] ] = 1;
cc[i]++;
}
}
if (cc[i] == 1) {
if (ans[0] != i)
ans[1] = i;
} else {
ans[ cc[i] ] = i;
}
}
for (int i = 0; i < p; i++)
pp[ans[i]] = i;
for (i = 0; i < p; i++)
printf("%d%c", pp[i], " \n"[i == p - 1]);
}