Simple 雜題練手記

Problem 1 世界上最可愛的珂朵莉

時間限制:C/C++ 1秒,空間限制:C/C++ 65536Kios

題目描述
我永遠喜歡珂朵莉~!
有兩個長爲n的序列a[i]與b[i]
你能夠把任意很少於x個a序列中的數變成y
你能夠把全部序列b中的數減去一個非負數t
你能夠把a序列和b序列分別任意打亂
要求對於1 <= i <= n知足a[i] >= b[i]
求t的最小值c++

輸入描述:
第一行三個數n,x,y
以後一行n個數表示a序列
以後一行n個數表示b序列測試

輸出描述
一行一個非負數表示答案
輸入示例1
輸入
10 0 233333
227849 218610 5732 128584 21857 183426 199367 211615 91725 110029
8064826 14174520 10263202 9863592 592727 7376631 5733314 1062933 12458325 15046167
輸出
14818318優化

數據範圍
對於100%的數據,0 <= n <= 200000 , 0 <= x,y <= 2000000000,0<=a[i],b[i]<=2000000000
---------------------spa

分析:
若是沒有1操做將a序列中的數變成y,則改題只須要將a和b分別排序,而後找出對應位置的最大差值便可。
如今有操做1,則先將a序列排好序,而後從小到大將a序列中的值與y依次比較,若是小於y,就更換。再從新對變換後的a序列排序,將a序列和b序列依次比較,尋找相應位置上最大的差值即爲全部答案!code

#include<bits/stdc++.h>
using namespace std;

int A[200010], B[200010];
 
int main()
{
    int n, x, y;
    scanf("%d%d%d", &n, &x, &y);
    for(int i = 0; i < n; i++) 
        scanf("%d", &A[i]);
    for(int i = 0; i < n; i++) 
        scanf("%d", &B[i]);
    sort(A, A+n);
    sort(B, B+n);
    for(int i = 0; i < n; i++)
    {
        if(x!=0 && A[i] < y) 
        {
            A[i] = y, x--;
        }
        if(x <= 0 || A[i] > y) break;
    }
    sort(A, A+n);
    int Ans = 0;
    for(int i = 0; i < n; i++) 
        Ans = max(Ans, B[i]-A[i]);
    printf("%d\n", Ans);
    return 0;
}

電池的壽命

總時間限制: 1000ms 內存限制: 65536kB排序

問題描述

小S新買了一個掌上游戲機,這個遊戲機由兩節5號電池供電。爲了保證可以長時間玩遊戲,他買了不少5號電池,這些電池的生產商不一樣,質量也有差別,於是使用壽命也有所不一樣,有的能使用5個小時,有的可能就只能使用3個小時。顯然若是他只有兩個電池一個能用5小時一個能用3小時,那麼他只能玩3個小時的遊戲,有一個電池剩下的電量沒法使用,可是若是他有更多的電池,就能夠更加充分地利用它們,好比他有三個電池分別能用三、三、5小時,他能夠先使用兩節能用3個小時的電池,使用半個小時後再把其中一個換成能使用5個小時的電池,兩個半小時後再把剩下的一節電池換成剛纔換下的電池(那個電池還能用2.5個小時),這樣總共就可使用5.5個小時,沒有一點浪費。
如今已知電池的數量和電池可以使用的時間,請你找一種方案使得使用時間儘量的長。遊戲

輸入格式

輸入包含多組數據。
輸入第一行,一個整數T,表示數據的組數。
接下來每組數據包括兩行,第一行是一個整數N (2 ≤ N ≤ 1000),表示電池的數目,第二行是N個正整數表示電池能使用的時間。ip

輸出格式

對每組數據輸出一行,表示電池能使用的時間,保留到小數點後1位。
樣例輸入
2
2
3 5
3
3 3 5
樣例輸出
3.0
5.5內存

問題分析

初看之下,本題感受沒有什麼很好的思路,但應該有貪心的辦法。
因爲每枚電池的使用時間不一樣,而咱們又要減小浪費才能使全部電池加起來用得最久,不難發現:若是咱們把使用時間最長的電池比喻成第一戰隊,其餘電池比喻成第二戰隊,使用時間就是戰鬥力,
每次從拿電池使用時間最長的和另外戰隊裏電池使用時間最長的相互戰鬥消耗1個戰鬥力;而且在每次戰鬥後,從新調整戰隊的分配狀況(最大電池容量可能發生了變化)。

事實上,你會發現:其實對於每一組數據只要判斷最大的那個數是否是比其他的數的和都要大,若是成立的話那固然就是剩下的全部電池與最大的電池車輪戰,最大值爲n-1個數的和,若是不成立的話那麼最大就是n個數的和的一半,也就是說電池是必定能夠所有用完的。講一下簡單的證實過程,每次先對N個數進行排序,而後最大電池每次與其他電池PK一小時,如此進行下去最後必然是三種狀況中的一種即(2 1 1)(1 1)(1 1 1),這三種狀況都是能夠用完的,因此電池一定會所有用完。

#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    int n,T;
    int buf[1000];
    double ans;
    cin>>T;
    for(int t=1;t<=T;++t)
    {
        ans=0;
        for(int i=0;i<n;i++){
            scanf("%d", &buf[i]);
            ans+=buf[i];
        }
        sort(buf,buf+n);
        if(buf[n-1]>ans-buf[n-1])
            ans=ans-buf[n-1];
        else
            ans=ans*1.0/2;
       printf("%.1f\n", ans);
    }
    return 0;
}

CJOJ P1236 - 指數序列求和

Description
\(1^b+2^b+…+a^b\) 的和除以10000的餘數。

Input
第一行包含一個正整數N,表示有N組測試數據
接下來N行每行包含兩個正整數a和b

Output
輸出共N行,每行一個對應的答案

Sample Input
1
2 3

Sample Output
9

Hint
數據範圍:
對於30%數據 \(n≤10,a,b≤1000\)
對於100%數據 \(n≤100,a,b≤10^9\)

分析
快速冪+同類餘數優化
暴力分30分不用解析了,就算你用了快速冪,for循環一遍,仍是30分。
for循環的時候循環枚舉到a是必定不可能的,咱們知道在咱們取膜的時候ac%b=a%bc%b,因此咱們利用這個原理,由於是挨着快速乘,他們取膜之後的數也必定是連着的,分析以後就會發現a^b和(a+mod)^b對答案的影響是同樣的,證實是顯然的。
因此說咱們對於任意 i^b 均可以寫成 (i%mod)^b ,因爲 mod 10000,模數只有一萬能夠推算出mod10000相同的數,分在一組,好比2333和23333和233333就分在一組。
而後,這一組有多少個數,我就把這個組的數快速冪求出b次方而後乘組中元素個數就好了(詳情看代碼)。

#include<bits/stdc++.h>
using namespace std;
int mod=10000;

int Pow(int x,int y)
{
    int base=x, cnt=1;
    while(y>0)
    {
        if(y%2==1)
            cnt=cnt*base%mod;
        base=base*base%mod;
        y=y>>1;
    }
    return cnt;
}

int main()
{
    int n,a,b,ans;
    cin>>n;
    while(n>0)
    {
        n=n-1, ans=0;
        cin>>a>>b;
        int k=min(mod-1,a);
        for(int i=1;i<=k;++i)
            //1~a範圍內餘數同爲i的一共有 1+(a-i)/mod 組,統計餘數相同的這組數的冪次方 
            ans=(ans+(1+(a-i)/mod)*Pow(i,b)%mod)%mod;
            
        cout<<ans<<endl;
    }
    return 0;
}

化學反應

Description

有 N 種不一樣的物質,每種物質有兩個屬性——「能量」和「活度」。 N 種中的任意兩種物質均可以發生反應;反應放熱爲兩種物質的「能量」之差加一再乘上「活度」的較大值。
換句話說,設第 i 種物質的能量和活度分別爲 Ai 和 Bi,則 i 和 j 反應的放熱爲 (| Ai-Aj |+1) * max(Bi, Bj)
如今你須要選出兩種物質,最小化它們反應放出的熱量。這個最小值是多少?

Input

本題包含多組測試數據,第一行爲測試數據組數 T。
對於每組數據:
第一行一個正整數 N,表示物質種類數。
接下來 N 行每行兩個正整數 Ai、 Bi,表示第 i 種物質的「能量」和「活度」。

Output

輸出一行一個正整數,最小放熱。 注意這個數可能須要 64 位整型來存儲。

Sample Input

1
7
19 5
5 6
1 2
8 4
25 10
12 3
9 6

Sample Output

12

數據範圍:

對於 40%的數據,N<=1000,T<=5
對於另外 20%的數據,N<=10^5,Ai、 Bi<=10^3,T=1
對於 100%的數據,N<=10^5,Ai、 Bi<=10^9,T<=40

分析:
40%的數據 $ N<=1000,O(n^2)$ 的複雜度將任意兩種物質進行兩兩反應,反應的最小值即爲所求答案。複雜度 \(O(T*n^2)\)
對於另外20%的數據,\(N<=10^5\),且 \(Ai Bi<=10^3,T=1\),能夠發現物品的種類數不少,可是能量和活度的值域很小。若是咱們對每種物質按照活度進行從小到大排序,本問題的關鍵在於找到 Bj<=Bi,且 | Aj-Ai |最小(即能量最接近i物質)的j物質
因爲 $ Bi<=10^3$,所以開vector值域活度的桶,將活度相同的物質丟進同一類桶中,從小到大排序後對於每個Bi,查找B1~Bi的桶內全部的元素並讓它們相互反應,最小的 | Ai-Aj |即爲在兩種物質活度最大值爲Bi時反應的最小熱量,
最後取整個反應裏的最小值即爲所求的答案。複雜度 \(O(T*10^3*n)\)
對於100%的數據,$ Ai Bi<=10^9$ 從新回到本題的關鍵問題,在於對於活度爲Bi的物質,要找到 Bj<=Bi,且 | Aj-Ai |最小(即能量最接近i物質)的j物質。
所以首先仍是按照活度從小到大進行排序,而後根據排序後物質的活度 Bi 從小到大進行枚舉,對於每個 Bi 查找前面已經枚舉完成的 j 物質(一定有Bj<=Bi),找到能量值剛好大於等於Ai的Aj,即爲兩種物質活度最大值爲Bi時反應的最小熱量,
接下來考慮如何查找 i 物質以前,能量值與 i 最接近的物質j,若是暴力去逐個比較,那麼最壞的複雜度依然會達到 \(O(n^2)\)。最快的查找方法固然是二分查找了,要想使用二分查找那麼i以前的物質能量屬性 Aj 應當維護一個有序序列。
怎麼維護物質i以前的能量屬性Aj有序呢?
方法①: 插入排序
方法②: Set
最終時間複雜度 $ O(T*nlogn) $ ,Set常數巨大,極可能會被卡掉

#include <cstdio>
#include <iostream>
#include <set>
#include <algorithm> 
using namespace std; 
#define l_b lower_bound
#define w1 first
#define w2 second
#define m_p make_pair
#define LL long long 
typedef pair<int,int> PII;
const int maxn=100005;
set<int> f;
set<int>::iterator lsh;
int T,N;
int a[maxn],b[maxn];
PII ls[maxn]; 
int main()
{    
    scanf("%d",&T);    
    for (int gb=1;gb<=T;gb++)    
    {        
        scanf("%d",&N);        
        for (int i=1;i<=N;i++) scanf("%d %d",&a[i],&b[i]);        
        for (int i=1;i<=N;i++) ls[i]=m_p(b[i],a[i]);        
        sort(ls+1,ls+N+1);        
        for (int i=1;i<=N;i++) a[i]=ls[i].w2,b[i]=ls[i].w1;        
        LL minc=1000000000;        
        minc=(LL)minc*minc;        
        f.clear();        
        for (int i=1;i<=N;i++)        
        {            
            if (i!=1)            // i不是第一個,去尋找i前面活度Bj<=Bi,且能量最接近ai的物質j 
            {                
                lsh=f.l_b(a[i]);  // 尋找i前面能量值第一個大於等於a[i]的位置              
                if (lsh!=f.end())                    
                    minc=min(minc,(LL)b[i]*((*lsh)-a[i]+1));                
                if (lsh!=f.begin())    // 尋找i前面能量值剛好小於a[i]的位置               
                {                    
                    --lsh;                    
                    minc=min(minc,(LL)b[i]*(a[i]-(*lsh)+1));                
                }            
            }            
            f.insert(a[i]);        
        }        
        cout<<minc<<endl;    
    }    
    return 0;
}
相關文章
相關標籤/搜索