【题目描述】
甲苯先生在制作一个online judge,他发现做比赛的人们很关心自己的排名(显而易见),在acm赛制的比赛中,如果通过题目数量不相等,则通过题目数量多的人排名更靠前,如果通过题目数量相等,则罚时更少的人排名更高。甲苯先生想让大家帮忙设计一个程序,每次有人通过之后,就告诉他排名在他的前面有多少人。(不包括和他罚时题数都相同的同学)
【输入格式】
第一行输入一个整数T表示样例数。对于每一个样例:输入三个整数m, n, seed。m表示参赛总人数(编号1−m),n表示一共有n次accept(假设accept已经去重,即不存在相同人的相同题目提交)。seed表示生成数据的种子。
接下来要求同学们使用之下的函数生成数据
typedef unsigned int ui;
ui randNum(ui& seed, ui last, const ui m) {
seed = seed * 17 + last;
return seed % m + 1;
}
(last为上一次输出的结果,在没有输出结果时last=7)
要求每次生成两个数据Ria, Rib 表示Ria的人Accept了一道题目,他的罚时为Rib。(也就是说Ria的题目数量+1,罚时长度+Rib)。
要求一共生成n组数据,代表一共有n次提交
对于所有数据,保证罚时总和不超过1500000
【输出格式】
每次提交输出一行整数,表示Ria在ac后比Ria成绩高的有多少选手。
S a m p l e I n p u t Sample~~Input Sample Input
1
7 3 1
S a m p l e O u t p u t Sample~~Output Sample Output
0
1
0
【题意分析】
每次操作根据randNum ()
函数生成Ria和Rib
用ac[i]
表示i位选手的ac数,fs[i]
相应地表示罚时
那么每次操作
a
c
[
R
i
a
]
+
+
,
f
s
[
R
i
a
]
+
=
R
i
b
ac[Ria]++,fs[Ria]+=Rib
ac[Ria]++,fs[Ria]+=Rib
有两个关键字,怎么办?上pair
然后套splay模板(记得一定要插哨兵,我就在这挂了),每个节点的值就是一个pair
pair的first是ac数,那么正常比较,second是罚时,越小的才排在前面,因此插入的时候取负就行了。
Code:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 1200100
#define INF 1 << 29
using namespace std;
typedef unsigned int ui;
typedef pair <int, int> pii;
int size[MAXN], son[MAXN][3], father[MAXN], cnt[MAXN], ac[MAXN], fs[MAXN], sz, root, n;
pii val[MAXN];
ui m, seed, last = 7;
ui randNum (ui &seed, ui last, ui m) {
seed = seed * 17 + last;
return seed % m + 1;
}
struct spaly {
inline void maintain (int x) {
size[x] = size[son[x][0]] + size[son[x][1]] + cnt[x];
}
inline void rotate (int x) {
int y = father[x], z = father[y];
int k = son[y][1] == x, kk = son[z][1] == y;
son[z][kk] = x,
father[x] = z,
son[y][k] = son[x][k ^ 1],
father[son[x][k ^ 1]] = y,
son[x][k ^ 1] = y,
father[y] = x,
maintain (y), maintain (x);
}
inline void splay (int x, int goal) {
while (father[x] != goal) {
int y = father[x], z = father[y];
if (z != goal)
(son[y][1] == x) ^ (son[z][1] == y)
? rotate (x) : rotate (y);
rotate (x);
}
if (! goal) root = x;
}
inline void find (pii x) {
int now = root;
while (son[now][x > val[now]] && val[now] != x)
now = son[now][x > val[now]];
splay (now, 0);
}
inline int prev (pii x) {
int now = root, pre;
while (now) {
(val[now] < x)
? pre = now, now = son[now][1]
: now = son[now][0];
}
return pre;
}
inline int succ (pii x) {
int now = root, nxt;
while (now) {
(val[now] > x)
? nxt = now, now = son[now][0]
: now = son[now][1];
}
return nxt;
}
inline void del (pii x) {
int pre = prev (x), nxt = succ (x);
splay (pre, 0), splay (nxt, pre);
int pos = son[nxt][0];
if (cnt[pos] > 1) cnt[pos]--, splay (pos, 0);
else son[nxt][0] = 0;
}
inline void insert (pii x) {
int now = root, fa = 0;
while (now && x != val[now]) fa = now, now = son[now][x > val[now]];
if (now) cnt[now]++;
else {
now = ++sz;
if (fa) son[fa][x > val[fa]] = now;
son[now][0] = son[now][1] = 0;
size[now] = cnt[now] = 1;
val[now] = x, father[now] = fa;
}
splay (now, 0);
}
}tree;
int main () {
int T; scanf ("%d", &T);
for (register int i = 1; i <= T; i++) {
scanf ("%d%d%d", &m, &n, &seed), root = 0, sz = 0;
tree.insert (pii (INF, -INF)), tree.insert (pii (-INF, INF));
memset (ac, 0, sizeof ac), memset (fs, 0, sizeof fs);
for (register int j = 1; j <= n; j++) {
ui o = randNum (seed, last, m), u = randNum (seed, last, m);
if (ac[o]) tree.del (pii (ac[o], -fs[o]));
++ac[o], fs[o] += u; tree.insert (pii (ac[o], -fs[o]));
last = size[son[root][1]] - 1, printf ("%d\n", last);
}
}
return 0;
}
然后你会发现你T飞了两个点,说明pair比较慢其实是我的程序常数太大
怎么办?加个火车头,pair换结构体+重载,勉强卡过10000ms。。。
为什么我的程序常数那么大
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
%:pragma GCC optimize("-fgcse")
%:pragma GCC optimize("-fgcse-lm")
%:pragma GCC optimize("-fipa-sra")
%:pragma GCC optimize("-ftree-pre")
%:pragma GCC optimize("-ftree-vrp")
%:pragma GCC optimize("-fpeephole2")
%:pragma GCC optimize("-ffast-math")
%:pragma GCC optimize("-fsched-spec")
%:pragma GCC optimize("unroll-loops")
%:pragma GCC optimize("-falign-jumps")
%:pragma GCC optimize("-falign-loops")
%:pragma GCC optimize("-falign-labels")
%:pragma GCC optimize("-fdevirtualize")
%:pragma GCC optimize("-fcaller-saves")
%:pragma GCC optimize("-fcrossjumping")
%:pragma GCC optimize("-fthread-jumps")
%:pragma GCC optimize("-funroll-loops")
%:pragma GCC optimize("-fwhole-program")
%:pragma GCC optimize("-freorder-blocks")
%:pragma GCC optimize("-fschedule-insns")
%:pragma GCC optimize("inline-functions")
%:pragma GCC optimize("-ftree-tail-merge")
%:pragma GCC optimize("-fschedule-insns2")
%:pragma GCC optimize("-fstrict-aliasing")
%:pragma GCC optimize("-fstrict-overflow")
%:pragma GCC optimize("-falign-functions")
%:pragma GCC optimize("-fcse-skip-blocks")
%:pragma GCC optimize("-fcse-follow-jumps")
%:pragma GCC optimize("-fsched-interblock")
%:pragma GCC optimize("-fpartial-inlining")
%:pragma GCC optimize("no-stack-protector")
%:pragma GCC optimize("-freorder-functions")
%:pragma GCC optimize("-findirect-inlining")
%:pragma GCC optimize("-fhoist-adjacent-loads")
%:pragma GCC optimize("-frerun-cse-after-loop")
%:pragma GCC optimize("inline-small-functions")
%:pragma GCC optimize("-finline-small-functions")
%:pragma GCC optimize("-ftree-switch-conversion")
%:pragma GCC optimize("-foptimize-sibling-calls")
%:pragma GCC optimize("-fexpensive-optimizations")
%:pragma GCC optimize("-funsafe-loop-optimizations")
%:pragma GCC optimize("inline-functions-called-once")
%:pragma GCC optimize("-fdelete-null-pointer-checks")
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXN 1200100
#define INF 1 << 29
using namespace std;
typedef unsigned int ui;
int size[MAXN], son[MAXN][3], father[MAXN], cnt[MAXN], ac[MAXN], fs[MAXN], sz, root, n;
ui m, seed, last = 7;
struct pii {
int ac, fs;
bool operator == (const pii &o) const {
return ac == o.ac && fs == o.fs;
}
bool operator < (const pii &o) const {
return ac < o.ac || (ac == o.ac && fs > o.fs);
}
bool operator > (const pii &o) const {
return ac > o.ac || (ac == o.ac && fs < o.fs);
}
bool operator != (const pii &o) const {
return ac != o.ac || (ac == o.ac && fs != o.fs);
}
}val[MAXN];
ui randNum (ui &seed, ui last, ui m) {
seed = seed * 17 + last;
return seed % m + 1;
}
void write (ui x) {
if (x > 9) write (x / 10);
putchar (x % 10 + '0');
}
struct spaly {
inline void maintain (int x) {
size[x] = size[son[x][0]] + size[son[x][1]] + cnt[x];
}
inline void rotate (int x) {
int y = father[x], z = father[y];
int k = son[y][1] == x, kk = son[z][1] == y;
son[z][kk] = x,
father[x] = z,
son[y][k] = son[x][k ^ 1],
father[son[x][k ^ 1]] = y,
son[x][k ^ 1] = y,
father[y] = x,
maintain (y), maintain (x);
}
inline void splay (int x, int goal) {
while (father[x] != goal) {
int y = father[x], z = father[y];
if (z != goal)
(son[y][1] == x) ^ (son[z][1] == y)
? rotate (x) : rotate (y);
rotate (x);
}
if (! goal) root = x;
}
inline void find (pii x) {
int now = root;
while (son[now][x > val[now]] && val[now] != x)
now = son[now][x > val[now]];
splay (now, 0);
}
inline int prev (pii x) {
int now = root, pre;
while (now) {
(val[now] < x)
? pre = now, now = son[now][1]
: now = son[now][0];
}
return pre;
}
inline int succ (pii x) {
int now = root, nxt;
while (now) {
(val[now] > x)
? nxt = now, now = son[now][0]
: now = son[now][1];
}
return nxt;
}
inline void del (pii x) {
int pre = prev (x), nxt = succ (x);
splay (pre, 0), splay (nxt, pre);
int pos = son[nxt][0];
if (cnt[pos] > 1) cnt[pos]--, splay (pos, 0);
else son[nxt][0] = 0;
}
inline void insert (pii x) {
int now = root, fa = 0;
while (now && x != val[now]) fa = now, now = son[now][x > val[now]];
if (now) cnt[now]++;
else {
now = ++sz;
if (fa) son[fa][x > val[fa]] = now;
son[now][0] = son[now][1] = 0;
size[now] = cnt[now] = 1;
val[now] = x, father[now] = fa;
}
splay (now, 0);
}
}tree;
int main () {
int T; scanf ("%d", &T);
for (register int i = 1; i <= T; i++) {
scanf ("%d%d%d", &m, &n, &seed), root = 0, sz = 0;
tree.insert (pii {INF, -INF}), tree.insert (pii {-INF, INF});
memset (ac, 0, sizeof ac), memset (fs, 0, sizeof fs);
for (register int j = 1; j <= n; j++) {
ui o = randNum (seed, last, m), u = randNum (seed, last, m);
if (ac[o]) tree.del (pii {ac[o], fs[o]});
++ac[o], fs[o] += u; tree.insert (pii {ac[o], fs[o]});
last = size[son[root][1]] - 1, write (last), puts ("");
}
}
return 0;
}