一开始的思路就是暴力,先求出最后一个值的位置op,然后遍历数组,找到第op个没有被占领的点,将最后一个值存到这个点,然而TLE了。
TLE代码
#include <iostream>
#include <cmath>
using namespace std;
int a[100001], ans[100001], book[100001];
//book[i]记录点i是否被占领
int main()
{
int n;
scanf("%d", &n);
int t = n;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= n; i++)
{
int op = sqrt(t);
t--;
int cnt = 0;
for (int j = 1; j <= n; j++)
{
if (book[j] == 0)
{
cnt++;
if (cnt == op)
{
book[j] = 1;
ans[j] = a[i];
}
}
}
}
for (int i = 1; i <= n; i++)
printf("%d%c", ans[i], i == n ? '\n ' : ' ');
}
然后在纸上模拟发现了一点规律,然后就打个表,好了,AC了。下面的打表的代码,当n=30时
从后往前遍历,每k个元素(k=3,5,7,9),将前k-1个元素放入答案数组尾部,1个元素放入答案数组头部,直到遍历完a数组就好了。
打表代码
#include <iostream>
#include <cmath>
using namespace std;
int a[100001], ans[100001], book[100001];
int main()
{
int n, x = 1;
scanf("%d", &n);
int t = n;
for (int i = 1; i <= n; i++)
a[i] = i;//scanf("%d", &a[i]);
for (int i = 1; i <= n; i++)
{
int op = sqrt(t);
t--;
int cnt = 0;
for (int j = 1; j <= n; j++)
{
if (book[j] == 0)
{
cnt++;
if (cnt == op)
{
book[j] = 1;
ans[x++] = a[j];
}
}
}
}
for (int i = 1; i <= n; i++)
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}
AC代码
#include <iostream>
#include <cmath>
using namespace std;
int a[100001], ans[100001];
int main()
{
int n, x = 3, f = 3;
scanf("%d", &n);
int head = 1, tail = n;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = n; i >= 1; i--)
{
if (n - i + 1 < x)
ans[tail--] = a[i];
else
{
ans[head++] = a[i];
f += 2;
x += f;
}
if (head > tail)
break;
}
for (int i = 1; i <= n; i++)
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}
/************************************************************** Problem: 1015 User: Language: C++ Result: 正确 Time:39 ms Memory:2804 kb ****************************************************************/