SY3-2-Queue
题目描述:
期末到了,N个学生准备去操场拍期末照。每个人有一个身高,排队结束后大家按顺序离开操场,每当一个人离开前就会拍一张照片。一张照片的奇怪程度定义为相邻的两个人的身高差平方之和。已知学生的身高和每个人的位置,按照读入顺序离开,你想知道照片奇怪值的期望值是多少。
答案用最简分数表示,若分母为1,则写成整数形式。
输入格式:
第一行一个N,表示人数
第二行N个正整数hi,按照离开操场顺序给出每一个学生的身高
第三行N个正整数pi,按照离开操场顺序给出每一个学生的位置
输出格式:
一行,一个分数,表示答案
样例输入:
3
6 5 8
2 1 3
样例输出:
14/3
数据范围:
2<=N<=500000, 1<=hi<=10000, 1<=pi<=N, 且若i≠j则pi≠pj
样例解释:
第一张照片为5 6 8,这张照片奇怪程度为5
位置2上的同学离开
第二张照片为5 8,这张照片奇怪程度为9
位置1上的同学离开
第二张照片为8,这张照片奇怪程度为0
————————————————————————————————————————————————
这道题因为有500万的数据,所以对数组进行排序是不现实的,因此在读入的时候就要一次到位,避免循环。
我们可以发现,每次拍完照片会有一个人出队,这时候如果他会有三种情况:
1.队首
2.队尾
3.队中
1和2是类似的情况,3是更加普遍的情况
对于情况3来说,设出队的人位置为i,其他的人的身高方差不变,减少了一个i-1与i的差平方,一个i,i+1的差平方,增加一个i-1,i+1的差平方。
我们可以维护一个初始情况下所有人的身高差平方差之和ans1,每次循环时将ans1进行如上所述的更新,并加入答案中。
在人出队以后需要将其去除,如果从数组中强行去除或者打上没了的标记时间复杂度会高,可以直接让i-1右边的位置变为i+1,i+1左边的位置变为i-1即可。
我们建立一个结构,含有三个成员:身高,左边的人的间隔,右边的人的间隔。
然后循环更新即可。
#include <stdio.h>
#include <string.h>
#include <math.h>
#define ll unsigned long long
struct node{
ll l, r, h;
}a[500010];
ll b[500010] = {0}, c[500010] = {0}, ans = 0, ans1 = 0;
ll gcd (ll a, ll b) { return b == 0 ? a : gcd (b, a % b); }
int main () {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%llu", &b[i]);
for (int i = 1; i <= n; i++) {
ll m;
scanf("%llu", &m);
a[m].h = b[i];
a[m].l = a[m].r = 1;
c[i] = m;
}
//for (int i = 1; i <= n; i++) printf("%llu\n", a[i].h);
for (int i = 1; i < n; i++) ans += (a[i].h - a[i + 1].h) * (a[i].h - a[i + 1].h);
ans1 = ans;
for (int i = 1; i <= n; i++) {
if (c[i] - a[c[i]].l >= 1 && c[i] + a[c[i]].r <= n) {
ans1 -= (a[c[i]].h - a[c[i] - a[c[i]].l].h) * (a[c[i]].h - a[c[i] - a[c[i]].l].h);
ans1 -= (a[c[i]].h - a[c[i] + a[c[i]].r].h) * (a[c[i]].h - a[c[i] + a[c[i]].r].h);
ans1 += (a[c[i] + a[c[i]].r].h - a[c[i] - a[c[i]].l].h) * (a[c[i] + a[c[i]].r].h - a[c[i] - a[c[i]].l].h);
a[c[i] - a[c[i]].l].r = a[c[i] + a[c[i]].r].l = a[c[i]].l + a[c[i]].r;
}
else if (c[i] - a[c[i]].l < 1 && c[i] + a[c[i]].r <= n) {
ans1 -= (a[c[i]].h - a[c[i] + a[c[i]].r].h) * (a[c[i]].h - a[c[i] + a[c[i]].r].h);
a[c[i] + a[c[i]].r].l = a[c[i]].l + a[c[i]].r;
}
else if (c[i] - a[c[i]].l >= 1 && c[i] + a[c[i]].r > n) {
ans1 -= (a[c[i]].h - a[c[i] - a[c[i]].l].h) * (a[c[i]].h - a[c[i] - a[c[i]].l].h);
a[c[i] - a[c[i]].l].r = a[c[i]].l + a[c[i]].r;
}
ans += ans1;
}
if (ans % n == 0) printf("%llu\n", ans / n);
else printf("%llu/%llu\n", ans / gcd (ans, n), n / gcd (ans, n));
return 0;
}