题解 P9472 [yLOI2022] 枕万梦
算法概述:
本题是一道非常典型的结构体排序的题。
题意讲解:
本题的大概意思就是给定 \(n\) 个数组的第一项,推算出数组的各项,对这 \(n\) 个数组都不同的一项进行对数组的排序。
暴力做法(30分)
这题大家最容易想到的方法就是将所有的数据算出来然后再去找 \(p\),但是如果我们看一眼数据范围:
- \(1 \le m \le 10^9\)
- \(1 \leq |a_{i,0}| \leq 10^9\)
咱先不说会不会 TLE,就这 \(a_{i,n}\) 乘出来都得炸long long,所以这种做法直接 Pass 掉。
(作者当时就用了这种做法,挂了70分)
满分做法
我们仔细看一看题目:第 \(i\) 个数列 \(a_i\) 满足递推式 \(a_{i,j} = a_{i,j - 1} \times i\)。
发现没有,推断 \(a_{i,j}\) 的递推式结尾乘上了一个 \(i\),这就能推断出以下内容。
\(p\) 只有一下两种情况:
- \(a_{i,0}\) 不相等,\(p = 0\)。
- \(a_{i,0}\) 相等,但因乘上一个 \(i\) 而导致 \(a_{i,1}\) 不相等,\(p = 1\)。
例:\(a_{1,0} = 1, a_{2,0} = 1\),根据递推公式推出 \(a_{1,1} = 1, a_{2,1} = 2\),\(p = 1\)。
由此我们可以看出,\(p\) 只有 0 和 1 两种情况,所以我们只算前两项就可以啦!
为了应对极端情况,记得开long long!
贴代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll n, m;
struct Node
{
ll a1, a2;
int id;
} a[100005];
bool cmp(Node x, Node y)
{
if (x.a1 != y.a1)
return x.a1 < y.a1;
else
return x.a2 < y.a2;
}
int main()
{
cin >> n >> m;
for (ll i = 1; i <= n; i++)
{
cin >> a[i].a1;
a[i].id = i;
a[i].a2 = a[i].a1 * i;
}
sort(a + 1, a + n + 1, cmp);
for (ll i = 1; i <= n; i++)
cout << a[i].id << " ";
cout << endl;
return 0;
}
附件:
30分暴力代码:
// 暴力用的是vector和结构体,代码略繁琐,建议不要使用。
#include <bits/stdc++.h>
using namespace std;
vector<int> a[100005];
int n, m;
struct Compare
{
int value;
int number;
} c[100005];
bool cmp(Compare x, Compare y)
{
return x.value < y.value;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
int x;
cin >> x;
a[i].push_back(x);
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j < m + 1; j++)
a[i].push_back(a[i][j - 1] * i);
}
int p;
for (p = 0; p < m + 1; p++)
{
bool flag = true;
for (int i = 1; i < n; i++)
{
if (!(a[i][p] != a[i + 1][p]))
{
flag = false;
break;
}
}
if (flag)
{
for (int i = 1; i <= n; i++)
{
c[i].value = a[i][p];
c[i].number = i;
}
break;
}
}
sort(c + 1, c + n + 1, cmp);
for (int i = 1; i <= n; i++)
cout << c[i].number << " ";
cout << endl;
return 0;
}

浙公网安备 33010602011771号