Educational Codeforces Round 131 (Rated for Div. 2)
Problem
有一个长度为n的a数组和b数组, 两者满足 b [ i ] = ⌊ i a [ i ] ⌋ b[i] =\lfloor \frac {i}{a[i]} \rfloor b[i]=⌊a[i]i⌋ 的对应关系。现在给出b数组,求出任意一个满足该对应关系的a数组。
Solution
- 首先可以发现:对于每个b[i],有一个与之对应的一段 a[i],且a[i] 满足 ⌊ i b [ i ] + 1 ⌋ + 1 ≤ a [ i ] ≤ ⌊ i b [ i ] ⌋ \lfloor \frac {i}{b[i] + 1}\rfloor + 1 \leq a[i] \leq \lfloor \frac {i}{b[i]}\rfloor ⌊b[i]+1i⌋+1≤a[i]≤⌊b[i]i⌋
- 然后可以贪心的对所有这些线段按照左端点从小到大排序;左端点相同时,按照右端点从小到大排序
但是,仅仅这样还不够 “贪”。
- 对于一个点 i ,可能会有很多段的左端点与之重合,可以选择右端点最小的一段,把i分给它。
- 然后对于剩余的,可以将他们与后面的左端点为i + 1的归为一类。然后把i + 1分配给其中右端点最小的一个。
- 对于剩余的,以此类推,归为后面的一类。
Code
#define pii pair<int, int>
const int N = 5e5 + 5, M = 1e6 + 7;
int a[N], b[N];
pair<pii, int> s[N];
int main()
{
IOS;
int T; cin >> T;
while (T--)
{
int n; cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> b[i];
//pair第一维是a[i]的范围,第二维是a[i]的下标i
if (b[i] == 0) s[i] = { {i + 1, n}, i };
else s[i] = { {i / (b[i] + 1) + 1, i / b[i]}, i };
}
sort(s + 1, s + n + 1, [](pair<pii, int> a, pair<pii, int> b) {
if (a.ft.ft == b.ft.ft) return a.ft.sd < b.ft.sd;
return a.ft.ft < b.ft.ft;
});
set<pii> se;//set堆顶是“最小值”
int j = 1;
for (int i = 1; i <= n; i++)
{
while (j <= n && s[j].ft.ft == i)
{
se.insert({ s[j].ft.sd, s[j].sd });
j++;
}
a[se.begin()->sd] = i;
se.erase(se.begin());
}
for (int i = 1; i <= n; i++)
cout << a[i] << " ";
cout << "\n";
//cout << "----------\n";
}
return 0;
}