題解【[USACO05NOV]奶牛玩雜技】

\[ \texttt{Description} \]spa

\(n\) 頭牛,每頭牛都有本身的體重 \(W_i\) 和力量 \(S_i\)code

將這 \(n\) 頭牛摞在一塊兒,每頭牛的壓扁指數定義爲:壓在該牛上面的牛的體重之和 \(-\) 該牛力量 。排序

您須要找到一種摞牛方案,使得壓扁指數最大的牛的壓扁指數最小。ip

求這個壓扁指數。
\[ \texttt{Solution} \]get

  • 微擾(鄰項交換)證實貪心好題。it

  • 考慮任意一個摞牛方案,設該摞牛方案中,從頂端往底端數的第 \(i\) 頭牛的體重爲 \(W_i\) ,力量爲 \(S_i\)
  • \(Z_i=\sum\limits_{j=1}\limits^{i}W_j\)(前 \(i\) 頭牛體重和)。io

  • 咱們考慮任意一個鄰項,考慮交換:table

\(i\) 頭牛 \(i+1\) 頭牛
交換前壓扁指數 \(Z_{i-1}-S_i\) \(Z_{i-1}+W_i-S_{i+1}\)
交換後壓扁指數 \(Z_{i-1}-S_{i+1}\) \(Z_{i-1}+W_{i+1}-S_i\)
  • 咱們發現須要比較這兩個式子的值:

\[ \max(Z_{i-1}-S_i,Z_{i-1}+W_i-S_{i+1}) \\ \max(Z_{i-1}-S_{i+1},Z_{i-1}+W_{i+1}-S_i) \]class

  • 式子內部減去 \(Z_{i-1}\) ,得:

\[ \max(-S_i,W_i-S_{i+1}) \\ \max(-S_{i+1},W_{i+1}-S_i) \]im

  • 式子內部加上 \(S_i+S_{i+1}\) ,得:

\[ \max(S_{i+1},W_i+S_i) \\ \max(S_i,W_{i+1}+S_{i+1}) \]

  • 注意到 \(W\) 爲正整數,因此有 \(S_i \leq W_i+S_i\)\(S_{i+1} \leq W_{i+1}+S_{i+1}\)
  • 也就是說當 \(S_{i+1} = \max(S_{i+1},W_i+S_i)\) 時,也定不會比 \(\max(S_i,W_{i+1}+S_{i+1})\) 大,另外一式子同理。
  • 故能夠轉化爲比較這兩個式子的值:

\[ W_i+S_i \\ W_{i+1}+S_{i+1} \]

  • \(W_i+S_i \leq W_{i+1}+S_{i+1}\) 時,上式 \(\leq\) 下式,則交換前定不比交換後優。
  • \(W_i+S_i \geq W_{i+1}+S_{i+1}\) 時,上式 \(\geq\) 下式,則交換後定不比交換前劣。

  • 咱們將知足 \(W_i+S_i > W_j+S_j\)\(i<j\) 的點對 \((i,j)\) 視爲一個逆序對,顯然,在任意局面下,增長逆序對的數量都不會使總體結果變優,減小逆序對的數量都不會使總體結果變差。
  • 根據冒泡排序,在任意局面下,均可經過鄰項交換使得該序列的逆序對數量變 \(0\) ,當逆序對數量爲 \(0\) 時,實際上就是將這 \(n\) 頭牛以 \(W_i+S_i\) 爲關鍵字從小到大排序。
  • 至此咱們就有一個貪心策略:將這 \(n\) 頭牛以 \(W_i+S_i\) 爲關鍵字從小到大排序儘管這個貪心策略很玄學。

  • 排好序,按題目描述說的同樣算出答案便可。
  • \(\mathcal{O(n \log n)}\)

\[ \texttt{Code} \]

#include<cstdio>
#include<algorithm>

#define RI register int

using namespace std;

inline int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}

const int N=50010;

int n;

struct Cow{
    int W,S;
}a[N];

bool cmp(Cow a,Cow b)
{
    return a.W+a.S<b.W+b.S;
}

long long ans=-0x3f3f3f3f;

int main()
{
    n=read();

    for(RI i=1;i<=n;i++)
        a[i].W=read(),a[i].S=read();

    sort(a+1,a+1+n,cmp);

    long long sum=0;
    for(RI i=1;i<=n;i++)
    {
        ans=max(ans,sum-a[i].S);
        sum+=a[i].W;
    }

    printf("%lld\n",ans); 

    return 0;
}

\[ \texttt{Thanks} \ \texttt{for} \ \texttt{watching} \]

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息