貪心-國王的遊戲(大數乘除)、連線子串

AC_no error發表於2020-10-22

目錄

 

國王的遊戲:

題目:

思路:

大資料高精度乘除模板:

乘:

除:模擬除法過程

程式碼:

連線子串

題目:

思路:

程式碼:​​​​​​​

國王的遊戲:

題目:

恰逢 H 國國慶,國王邀請 n 位大臣來玩一個有獎遊戲。首先,他讓每個大臣在左、右手上面分別寫下一個整數,國王自己也在左、右手上各寫一個整數。然後,讓這 n 位大臣排成一排,國王站在隊伍的最前面。排好隊後,所有的大臣都會獲得國王獎賞的若干金幣,每位大臣獲得的金幣數分別是:排在該大臣前面的所有人的左手上的數的乘積除以他自己右手上的數,然後向下取整得到的結果。
國王不希望某一個大臣獲得特別多的獎賞,所以他想請你幫他重新安排一下隊伍的順序,使得獲得獎賞最多的大臣,所獲獎賞儘可能的少。注意,國王的位置始終在隊伍的最前面。

 

對於 20%的資料,有 1≤ n≤ 10,0 < a,b < 8 ;
對於 40%的資料,有 1≤ n≤20,0 <a,b<8 ;

對於 60%的資料,有 1≤ n≤100 ;

對於 60%的資料,保證答案不超過 109 ;

對於 100%的資料,有 1 ≤ n ≤1,000,0 < a,b < 10000 。

思路:

儘可能少,確定貪心策略,發現兩個大臣互換位置對其它大臣獲得獎賞數量沒有影響,比較下換位置前和換位置後哪一個最大的較小。

前k個大臣左手乘積為L,第k+1個大臣L1,R1,第k+2個大臣L2,R2;假設讓第k+1個大臣在前面更適合,當他在前時,最大值為max(L/R1①,L*L1/R2②),當他在後面時,最大值為max(L/R2③,L*L2/R1④);讓他在前面更合適,那麼就要保證前者的max小於後者的max,顯然①<④,③<②,那麼後者肯定要選擇④(如果選②必定比前者小,因為他小於③)。這樣只要能保證②<④即可,化簡得L1*R1<L2*R2。由此可得,對於任意兩個大臣,左右手數相乘小的靠前獲得的最大值最小。

         資料範圍感人,10000個大臣,每個大人最多10000,那就是10000^10000。接下來看下高精度大數乘除:

陣列儲存大資料乘法,可以理解為把每一位拆分為(xn*10^n……..x1*10+x0*1)*x對每一位乘,一旦係數大於10,就可以進位了,注意的是,每一位都要僅為,因為每一位數都可能大於9。所以至少迴圈len次。

大資料高精度乘除模板:

乘:

void mul(ll x){

         for(int i = 1;i <= len;i++)

                  num[i] = num[i]*x;

         int cnt = 1;

         while(num[cnt] > 9||cnt <= len){//個位無進位不代表其他位無進位

                  num[cnt+1] += num[cnt]/10;

                  num[cnt]%=10;

                  cnt++;

         }

         len=cnt;

         if(!num[len])      len--;

         return ;

}

除:模擬除法過程

void div(ll x){

         for(int i = len;i >= 1;i--){

                  num[i-1] += (num[i]%x)*10;

                  num[i]/=x;

         }

         while(!num[len]) len--;

}

程式碼:

#include<algorithm>

#include<iostream>

#include<cstring>

#include<string>

#include<cstdlib>

#include<map>

#include<cmath>

#include<vector>



using namespace std;

typedef long long  ll;

const int maxn = 1e5+50;

typedef struct{

         ll l;

         ll r;

         ll z;

}hand;

hand arr[maxn];

int len,n;

ll num[maxn];//最多1e5個1e4相乘 也就是4e5+1位數

bool cmp(hand a,hand b){

         return a.z < b.z;//奇葩 等號竟然沒過。

}

void mul(ll x){

         for(int i = 1;i <= len;i++)

                  num[i] = num[i]*x;

         int cnt = 1;

         while(num[cnt] > 9||cnt <= len){//個位無進位不代表其他位無進位

                  num[cnt+1] += num[cnt]/10;

                  num[cnt]%=10;

                  cnt++;

         }

         len=cnt;

         if(!num[len])      len--;

         return ;

}

void div(ll x){

         for(int i = len;i >= 1;i--){

                  num[i-1] += (num[i]%x)*10;

                  num[i]/=x;

         }

         while(!num[len]) len--;

}

int main(){

         cin >> n;

         cin >> arr[0].l >> arr[0].r;

         for(int i = 1;i <= n;i++){

                  cin >> arr[i].l >> arr[i].r;

                  arr[i].z = arr[i].l*arr[i].r;

         }

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

         len=1;num[1]=1;

         for(int i = 0;i<n;i++)    mul(arr[i].l);

         div(arr[n].r);

         for(int i = len;i >= 1;i--)        cout<<num[i];

         if (!len) printf("1");

         return 0;

}

連線子串

題目:

設有n個正整數(n ≤ 20),將它們聯接成一排,組成一個最大的多位整數。

例如:n=3時,3個整數13,312,343聯接成的最大整數為:34331213

又如:n=4時,4個整數7,13,4,246聯接成的最大整數為:7424613

輸入描述:

第一行,一個正整數n。

第二行,n個正整數。

輸出描述:

一個正整數,表示最大的整數

思路:

不可以直接判斷字典序:23 2323231 or 33  331  9錯誤,如果想著判斷這些特例就會很麻煩。

同樣,任何相鄰的兩個子串交換不會影響其它子串的貢獻,就看一下互換前後哪一種最大。

現在感覺在冒泡。最後只要能達到任何兩個相鄰子串互換都不如不換,就是最大字典序了。

假設對子串s1…sm…sn….. 如果sm和sn交換更好的話,sm+1在sn前面又更好些,sm+2在sn前面又更好些(因為之前肯定比較過了在sn前面更好)……最後又回到了原來的位置。

         冒泡複雜度太高,冒泡就是排序,不如直接快排,sort函式cmp一下就可以了。

bool cmp(string a,string b){

         return a+b>b+a;

}

程式碼:

#include<algorithm>

#include<iostream>

#include<cstring>

#include<string>

#include<cstdlib>

#include<map>

#include<cmath>

#include<vector>

//思路:....AB...若想讓序列最大 保證每一對相鄰的A+B>B+A即可,轉化為排序。

//不可以直接判斷字典序:23 2323231 or 33  331  9錯誤

using namespace std;

typedef long long ll;

const int maxn = 1e6+50;

string s[30];

string ans;

bool cmp(string a,string b){

            return a+b>b+a;

}

int main(){

            int n;

            cin >> n;

            for(int i = 0;i < n;i++)        cin>>s[i];

            sort(s,s+n,cmp);

            for(int i = 0;i < n;i++)        ans+=s[i];

            cout << ans;

            return 0;

}

 

相關文章