参考:http://blog.csdn.net/qq_35078631/article/details/58669520
问题描述
从万能词典来的聪明的海狸已经使我们惊讶了一次。他开发了一种新的计算器,他将此命名为"Beaver's Calculator 1.0"。它非常特别,并且被计划使用在各种各样的科学问题中。
为了测试它,聪明的海狸邀请了n位科学家,编号从1到n。第i位科学家给这个计算器带来了 ki个计算题。第i个科学家带来的问题编号1到n,并且它们必须按照编号一个一个计算,因为对于每个问题的计算都必须依赖前一个问题的计算结果。
每个教授的每个问题都用一个数 ai, j 来描述,i(1≤i≤n)是科学家的编号,j(1≤j≤ ki )是问题的编号, ai, j 表示解决这个问题所需资源单位的数量。
这个计算器非常不凡。它一个接一个的解决问题。在一个问题解决后,并且在下一个问题被计算前,计算器分配或解放资源。
计算器中最昂贵的操作是解放资源,解放远远慢于分配。所以对计算器而言,每一个接下来的问题所需的资源不少于前一个,是非常重要的。
给你关于这些科学家所给问题的相关信息。你需要给这些问题安排一个顺序,使得“坏对”尽可能少。
所谓“坏对”,就是相邻两个问题中,后一个问题需求的资源比前一个问题少。别忘了,对于同一个科学家给出的问题,计算它们的相对顺序必须是固定的。
为了测试它,聪明的海狸邀请了n位科学家,编号从1到n。第i位科学家给这个计算器带来了 ki个计算题。第i个科学家带来的问题编号1到n,并且它们必须按照编号一个一个计算,因为对于每个问题的计算都必须依赖前一个问题的计算结果。
每个教授的每个问题都用一个数 ai, j 来描述,i(1≤i≤n)是科学家的编号,j(1≤j≤ ki )是问题的编号, ai, j 表示解决这个问题所需资源单位的数量。
这个计算器非常不凡。它一个接一个的解决问题。在一个问题解决后,并且在下一个问题被计算前,计算器分配或解放资源。
计算器中最昂贵的操作是解放资源,解放远远慢于分配。所以对计算器而言,每一个接下来的问题所需的资源不少于前一个,是非常重要的。
给你关于这些科学家所给问题的相关信息。你需要给这些问题安排一个顺序,使得“坏对”尽可能少。
所谓“坏对”,就是相邻两个问题中,后一个问题需求的资源比前一个问题少。别忘了,对于同一个科学家给出的问题,计算它们的相对顺序必须是固定的。
输入格式
第一行包含一个整数n,表示科学家的人数。接下来n行每行有5个整数,ki, ai, 1, xi, yi, mi (0 ≤ ai, 1 < mi ≤ 109, 1 ≤ xi, yi ≤ 109) ,分别表示第i个科学家的问题个数,第1个问题所需资源单位数,以及3个用来计算 ai, j 的参量。ai, j = (ai, j - 1 * xi + yi)mod mi。
输出格式
第一行输出一个整数,表示最优顺序下最少的“坏对”个数。
如果问题的总个数不超过200000,接下来输出 行,表示解决问题的最优顺序。每一行两个用空格隔开的整数,表示这个问题所需的资源单位数和提供这个问题的科学家的编号。
如果问题的总个数不超过200000,接下来输出 行,表示解决问题的最优顺序。每一行两个用空格隔开的整数,表示这个问题所需的资源单位数和提供这个问题的科学家的编号。
样例输入
2
2 1 1 1 10
2 3 1 1 10
2 1 1 1 10
2 3 1 1 10
样例输出
0
1 1
2 1
3 2
4 2
1 1
2 1
3 2
4 2
数据规模和约定
20%的数据 n = 2, 1 ≤ ki ≤ 2000;
另外30%的数据 n = 2, 1 ≤ ki ≤ 200000;
剩下50%的数据 1 ≤ n ≤ 5000, 1 ≤ ki ≤ 5000。
另外30%的数据 n = 2, 1 ≤ ki ≤ 200000;
剩下50%的数据 1 ≤ n ≤ 5000, 1 ≤ ki ≤ 5000。
问题分析:首先我们需要确定的是,同一个科学家提出问题的相对顺序必须是固定的,然后每个科学家提出问题的序列中均可能存在“坏对”。
1、我们所需要求的最优顺序下最少的“坏对”个数,就是所有科学家所提出的问题的序列中的最多“坏对”的个数,即为所求。
2、之后求解最优顺序的做法就是利用归并排序将科学家的任务分为几个升序段进行排序(利用归并排序的原因是,其并不改变序列的相对顺序)
1 #include<bits/stdc++.h> 2 using namespace std; 3 struct node 4 { 5 int pos, count;//pos为当前位置,count数量 6 long long num[5001];//存储资源数 7 }p[5001]; 8 9 struct ms 10 { 11 long long number, id;//number为资源数,id为第几个科学家 12 }ans[200001], temp[200001]; 13 14 void merge(int x, int y) 15 { 16 int mid = (x + y) / 2; 17 int t1 = x; 18 int t2 = mid + 1; 19 int index = x; 20 while(t1 != mid + 1 && t2 != y + 1) 21 { 22 if(ans[t1].number <= ans[t2].number) 23 { 24 temp[index].id = ans[t1].id; 25 temp[index++].number = ans[t1++].number; 26 } 27 else 28 { 29 temp[index].id = ans[t2].id; 30 temp[index++].number = ans[t2++].number; 31 } 32 } 33 while(t1 <= mid) 34 { 35 temp[index].id = ans[t1].id; 36 temp[index++].number = ans[t1++].number; 37 } 38 while(t2 <= y) 39 { 40 temp[index].id = ans[t2].id; 41 temp[index++].number = ans[t2++].number; 42 } 43 for(int i=x;i<=y;i++) 44 { 45 ans[i]=temp[i]; 46 } 47 } 48 49 void mergesort(int st, int en) 50 { 51 if(st < en) 52 { 53 int mid = (en + st) / 2; 54 mergesort(st, mid); 55 mergesort(mid + 1, en); 56 merge(st, en); 57 } 58 } 59 60 int main() 61 { 62 int n; 63 cin >> n; 64 int length = 0;//总问题数 65 int sum = 0; 66 int result = 0;//“坏对” 67 long long k, a, x, y, m; 68 for(int i = 1; i <= n; i++) 69 { 70 sum = 0; 71 cin >> k >> a >> x >> y >> m; 72 length += k; 73 p[i].pos = 1; 74 p[i].count = k; 75 p[i].num[1] = a; 76 for(int j = 2; j <= k; j++) 77 { 78 p[i].num[j] = (p[i].num[j - 1] * x + y) % m; 79 if(p[i].num[j] < p[i].num[j - 1]) 80 { 81 sum++; 82 } 83 } 84 result = max(sum, result); 85 } 86 cout << result << endl; 87 if(length <= 200000)//题目要求 88 { 89 int st = 1, en = 1; 90 while(en <= length) 91 { 92 for(int i = 1; i <= n; i++) 93 { 94 int position = p[i].count + 1;//假设未出现坏对,一直到最后的序列 95 for(int j = p[i].pos; j <= p[i].count; j++) 96 { 97 if(p[i].num[j] < p[i].num[j - 1] && j != p[i].pos)//不满足条件,且不是第一个位置元素(“坏对”也要插入) 98 { 99 position = j;//更新位置 100 break; 101 } 102 ans[en].id = i; 103 ans[en++].number = p[i].num[j]; 104 } 105 p[i].pos = position;//更新位置 106 } 107 mergesort(st, en - 1); 108 st = en; 109 } 110 for(int i = 1; i <= length; i++) 111 cout << ans[i].number << " " << ans[i].id << endl; 112 } 113 }