洛谷 P1080 國王遊戲 題解
阿新 • • 發佈:2020-07-10
原題
思路
分析
我們先假設隊伍如下:
People | left hand | right hand |
---|---|---|
Before | \(S_a\) | |
A | \(a_1\) | \(b_1\) |
B | \(a_2\) | \(b_2\) |
After | \(S_b\) |
現在我們要交換A、B,隊伍如下:
People | left hand | right hand |
---|---|---|
Before | \(S_a\) | |
B | \(a_2\) | \(b_2\) |
A | \(a_1\) | \(b_1\) |
After | \(S_b\) |
我們可以發現:這樣交換對於Before
和 After
部分的結果沒有影響,只對A
B
的部分結果有影響。對於交換前的答案:
\(ans1=\max\{\dfrac{S_a}{b_1},\dfrac{S_a\times a_1}{b_2}\}\)
對於交換後的答案:
\(ans2=\max\{\dfrac{S_a}{b_2},\dfrac{S_a\times a_2}{b_1}\}\)
我們知道,這些數都是大於等於\(1\)的正整數,於是:
\(\dfrac{S_a\times a_1}{b_2} \ge \dfrac{S_a}{b_2}\)
\(\dfrac{S_a\times a_2}{b_1} \ge \dfrac{S_a}{b_1}\)
因此,當我們假定 \(ans1 < ans2\)
\(\dfrac{S_a\times a_1}{b_2} < \dfrac{S_a\times a_2}{b_1}\)
化簡得:
\(a_1\times a_2 < b_1 \times b_2\)
演算法
顯然,此關係滿足傳遞性,即當
\(a_1\times a_2 < b_1 \times b_2\)
\(b_1\times b_2 < c_1 \times c_2\)
有:
\(a_1\times a_2 < c_1 \times c_2\)
因此,我們可以貪心,只要按此規則排序,再統計答案即可,注意要高精
程式碼
壓位高精:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; #define ll long long const int MAXN = 1010; const int base = 10000; int n; struct people{ int x,y; bool operator < (const people &b ) const { return (ll)x * y < (ll)b.x * b.y; } }peo[MAXN]; struct bignum{//only mul ,comp ans so on int a[1020],len; bignum() {//初始化 memset(a,0,sizeof(a)); len = 1; } void resize(){//限制位數 len = 1010; for(int i = len - 1;i >= 0;i--) if( a[i] > 0 ) { len = i + 1; return; } len = 1; } bool operator < (const bignum &b) const{//比大小 if ( len != b.len) return len < b.len; for(int i = len - 1 ;i >= 0 ;i--){ if(a[i] != b.a[i]) return a[i] < b.a[i]; } return 0; } bignum operator * (const int &b) const{ //乘法(高精乘int) bignum c; for(int i = 0; i < len ;i++){ c.a[i] += a[i] * b; if( c.a[i] >= base) { c.a[i+1] += c.a[i]/base; c.a[i] %= base; } } c.resize(); return c; } bignum operator / (const int &b) const{//除法(高精除int) ll temp = 0; bignum c; if( b == 0) { printf("Error!"); return c; } for(int i = len -1;i >= 0;i--){ temp = temp * base + a[i]; if(temp >= b) { c.a[i] = temp / b; temp %= b; } } c.resize(); return c; } void print (){//輸出 resize(); printf("%d",a[len-1]); if ( len > 1) for(int i = len - 2;i >=0;i--){ printf("%04d",a[i]); } return; } }; int main (){ scanf("%d",&n); for(int i = 0;i <= n;i++){ scanf("%d %d",&peo[i].x,&peo[i].y); } sort(peo+1,peo+n+1); bignum ans,tot; tot.a[0] = 1 ; tot = tot * peo[0].x; for(int i = 1;i <= n;i++){ bignum temp = tot / peo[i].y; tot = tot * peo[i].x; if( ans < temp ) ans = temp; } ans.print(); return 0; }
反思總結
應該是太久沒寫壓位高精了,打錯了INF
回,我有幾個出錯的地方:
- 在
resize()
函式裡未在最後設定len=1
,導致數為0時len
很大 resize()
函式裡面把return
寫成break;
,導致每個被resize()
的數的len=1
base
可以去1e5
但只取了1e4
print()
函式裡面輸出記憶錯誤:
printf("%4d",a[i]);
顯然,少了0
5. *
函式裡面寫成了:
bignum operator * (const int &b) const{
bignum c;
for(int i = 0; i < len ;i++){
c.a[i] = a[i] * b;
if( c.a[i] >= base) {
c.a[i+1] += c.a[i]/base;
c.a[i] %= base;
}
}
c.resize();
return c;
}
總的來說,我也要多練習壓位高精……