Table of Contents
1. P1803 凌乱的yyy / 线段覆盖
思路:
这道题的思路仍然是排序之后扫一遍就可以,这里的核心思想是把n场考试缩减成n-1的子问题,为了使子问题有最优解,就需要确保缩减的时候挑出的第一场考试结束时间尽可能短,所以排序的时候应该以结束时间的早晚进行排序,然后比较:如果某考试的开始时间大于等于上一场选中的考试的结束时间,就可以选择。练手题,两遍AC。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include<bits/stdc++.h>
using namespace std;
int n, x, y; vector<pair<int, int> > nums; int tail, cnt;
bool cmp(pair<int, int> a, pair<int, int> b){ return a.second == b.second ? a.first < b.first : a.second < b.second; } int main(){ scanf("%d", &n); for(int i = 0; i < n; i++){ scanf("%d%d", &x, &y); nums.push_back(make_pair(x, y)); } sort(nums.begin(), nums.end(), cmp); for(int i = 0; i < n; i++){
if(nums[i].first >= tail){ tail = nums[i].second; cnt++; } } cout<<cnt<<endl; return 0; }
|
2. P1080 国王游戏
思路:
这道题比较难也比较经典,思路非常有趣:
首先可以明确的一点是:在某个大臣前面的人无论怎么排都不会影响该大臣得到的钱(乘法交换律)。只有当A和B的相对位置发生变化的时候,A和B得到的钱数才会互相影响(这里相对位置指的是A在B前或者B在A钱)。那么考虑: $ A(a_i, b_i)$ 和$ B(a_j, b_j)$的位置顺序(国王$ (a_0, b_0)$永远在最前面):
- A在B的前面,则设A得到的金币为$ \prod_{a_1}^{a_{i-1} }/b_i$,B得到的金币为$ \prod_{a_1}^{a_{i-1} }a_i\prod_{a_{i+1} }^{a_{j-1} }/b_j$, $ans1=max(\prod_{a_1}^{a_{i-1} }/b_i, \ \ \prod_{a_1}^{a_{i-1} }a_i\prod_{a_{i+1}}^{a_{j-1}}/b_j)$;
- A在B的后面,则B得到的金币为$ \prod_{a_1}^{a_{i-1} }/b_j$,A得到的金币为$ \prod_{a_1}^{a_{i-1} }a_j\prod_{a_{i+1}}^{a_{j-1}}/b_i$,$ans2=max(\prod_{a_1}^{a_{i-1} }a_j\prod_{a_{i+1}}^{a_{j-1} }/b_i,\ \ \prod_{a_1}^{a_{i-1} }/b_j)$
显然,ans1的左项小于ans2的左项,ans1的右项大于ans2的右项,因此实际上比较ans1和ans2的大小就是在比较ans1右项和ans2的左项:
$if\ ans1.right < ans2.left, then\ a_i/b_j<a_j/b_i,\ then\ a_ib_i<a_jb_j$
也即,如果ans1 < ans2,那么就有$ a_ib_i<a_jb_j$。且这是充要条件。
因此,要得到最小的最大值,假设A的a*b值大于B,那么显然ans1要大于ans2,这个时候为了取到ans2(尽可能小的最大值),就要让A(a*b值大的大臣)排在B(a*b值小)的大臣后面。
刚才已经说过,每个大臣前面的人怎么排序并不会影响他应得的钱。因此最后的解一定是最优解。
这个思路有了以后,再看这道题,注意数据范围,需要用到高精度:
高精度可以通过struct封装常用的乘法、除法、=、<等运算实现,需要注意的几点:
- 一般高精度每一个位的整数大小(base取10000),再大并不会提高效率,并且1000x10000尚未溢出整数范围,对乘法有好处。
- data[N]的最低位data[0]存该大数的“位数”(除data[0]以外的数组长度)。
- 除法的时候需要保证前导零不被输出。
- 输出的时候,先输出最高位(data[data[0]]),然后输出其他位,如果base=10000则应在输出的时候输出“%04d”对应中间位输出长度。
最后代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
| #include<bits/stdc++.h>
using namespace std;
const int N = 10000+5; int n, x, y; vector<pair<int, int> > nums;
bool cmp(pair<int, int> a, pair<int, int> b){ long long xx = a.first*a.second, yy = b.second*b.first; return xx < yy;
}
struct BigInt{ static const int base = 10000; int data[N];
BigInt(long long num = 0){ *this = num; } BigInt operator = (long long num){ memset(data, 0, sizeof(data)); for(int i = 1; num > 0; i++){ data[i] = num % base; num /= base; data[0]++; } } void multi(int num){ for(int i = 1; i <= data[0]; i++) data[i] *= num; for(int i = 1; i < data[0]; i++){ data[i + 1] += data[i] / base; data[i] %= base; } while(data[data[0]]>=base){ data[data[0] + 1] += data[data[0]] / base; data[data[0]] %= base; data[0]++; } } void div(int num){ int q = 0; for(int i = data[0]; i > 0; i--) { q *= base; q += data[i]; data[i] = q/num; if(data[0] == 0 && data[i] != 0) { data[0]=i; } q %= num; } for(int i = data[0]; i > 0; i--){ if(data[i] == 0) data[0]--; else break; } } void print(){ printf("%d", data[data[0]]); for(int i = data[0]-1; i > 0; i--) printf("%04d", data[i]); puts(""); } bool compare(BigInt& b){ if(data[0] > b.data[0]) return true; else if (data[0] < b.data[0]) return false; else{ for(int i = data[0]; i > 0; i--){ if(data[i] > b.data[i]) return true; else if (data[i] < b.data[i]) return false; } return true; } } BigInt (BigInt& b){ memset(data,0,sizeof(data)); for(int i = b.data[0];i >=0; i--) data[i] = b.data[i]; return ; } void mod(int num){ data[0] = 1; data[1] %= num; for(int i = 2; i <= data[0]; i++) data[i] = 0; } }ans, accu;
int main(){ scanf("%d", &n); for(int i = 0; i <= n; i++){ scanf("%d%d", &x, &y); nums.push_back(make_pair(x,y)); } sort(nums.begin()+1, nums.end(), cmp); accu = nums[0].first; ans = 0; for(int i = 1; i <= n; i++){ BigInt temp = accu; temp.div(nums[i].second); if(temp.compare(ans)){ ans = temp; } accu.multi(nums[i].first); } ans.print(); return 0; }
|
这道题被高精度卡了好久。。。