P3087 题解
题意
有
思路
每类属性实际上就是进制中的一位,所有属性构成一个混合进制。
首先我们要求出每一位的进率,和每只奶牛在每一位上对应的值,可以对每⼀类属性的值排序,然后去重,按顺序
从
然后就可以将每只奶牛对应的混合进制数转换成最小单位数量,排序后这些数将数轴分成
复杂度
令属性类的数量为
时间
属性值总数
- 判断每个属性是否首次出现
\mathcal O(N) ,注意常数为属性⻓度10 。 - 计算属性对应的数值
\mathcal O(N) ,注意常数为属性⻓度10 。 - 计算进制转换对应的值
\mathcal O(1) 。
奶牛对应的十进制数排序
寻找第
转换回混合进制
总时间复杂度为
空间
记录属性
代码
#include <algorithm>
#include <iostream>
using namespace std;
const int kMaxN = 102, kMaxL = 31;
struct P { // 属性种类
int r, w; // 位权、进率
string s[kMaxN]; // 位上的数对应的属性值
} p[kMaxL];
string s[kMaxN][kMaxL], str;
int b[kMaxN][kMaxL], v[kMaxN], n, k, l, x;
int main() {
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> str >> str >> str >> str;
for (l = 0;; l++) { // 读入属性
cin >> str;
if (str == "cow.") { // 属性结束
break;
}
s[i][l] = str, b[i][l] = 1; // 记录属性、初始化首次出现标记
for (int j = 1; j < i; j++) { // 枚举之前的同类属性
b[i][l] &= s[j][l] != s[i][l]; // 判重标记是否首次出现
}
}
}
for (int k = l - 1; k >= 0; k--) { // 权重由低到高枚举属性类型
p[k].w = k == l - 1 ? 1 : p[k + 1].w * p[k + 1].r; // 计算当前属性的位权
for (int i = 1; i <= n; i++) { // 枚举每只奶牛
int c = 0; // 初始化位上的值
for (int j = 1; j <= n; j++) { // 枚举其他奶牛
c += b[j][k] && s[j][k] < s[i][k]; // 计算较小同类属性数量
}
p[k].r = max(p[k].r, c + 1); // 更新进率
p[k].s[c] = s[i][k]; // 记录值对应的属性
v[i] += c * p[k].w; // 累加位对应的值
}
}
sort(v + 1, v + 1 + n); // 将拥有的奶牛按值排序
v[0] = -1, v[n + 1] = 1e9 + 1; // 初始化边界
for (int i = 1; i <= n + 1; i++) { // 枚举缝隙寻找第k只
if (k <= v[i] - v[i - 1] - 1) { // 在当前缝隙中
x = v[i - 1] + k;
break;
} else {
k -= v[i] - v[i - 1] - 1; // 减去当前缝隙长度
}
}
for (int i = 0; i < l; i++) { // 值转混合进制
int y = x / p[i].w % p[i].r; // 计算位上的值
cout << (i ? " " : "") << p[i].s[y];
}
return 0;
}