Codeforces Round #521

A題
res = a*(k - k/2) - b*(k/2)
注意用long long
B 題
改變最小的a,使得序列中不存在1 0 1的情況。
掃描一遍,遇到101的時候,把後面一個1給翻轉成0,然後記錄一下次數輸出。

C 題
題意,一個序列如果其中N-1個數的和與另一個數相等,那麼該序列是good
給你一個序列,多少中方法,可以刪除一個aj,使得這個序列爲good

思路:
直接考慮枚舉即可,注意記錄每個數的位置,排序後,記錄前N-1個數的和,以及最後一個數。從1開始掃描,判斷刪除這個數後,該序列是否爲good,最後注意再判斷一下刪除第N個元素後是否符合。

代碼如下:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 2e5+10;
typedef long long ll;
class Node{
public:
    ll v;
    int p;
};
int N;
Node q[MAX];
bool cmp(Node A,Node B){
    return A.v < B.v;
}
int main(void){
    scanf("%d",&N);
    for(int i=1;i<=N;++i){
        scanf("%lld",&q[i].v);
        q[i].p = i;
    }
    sort(q+1,q+1+N,cmp);
    ll sum = 0,Max = q[N].v;
    for(int i = 1;i<=N-1;++i){
        sum += q[i].v;
    }
    vector<int> vec;
    for(int i=1;i<=N-1;++i){
        if(sum - q[i].v == Max){
            vec.push_back(q[i].p);
        }
    }
    if(sum - q[N-1].v == q[N-1].v)
        vec.push_back(q[N].p);
    printf("%d\n",(int)vec.size());
    for(int i=0;i<vec.size();++i){
        printf("%d",vec[i]);
        if(i != vec.size()-1)
            printf(" ");
        else
            printf("\n");
    }
    return 0;
}

D題
題意:給你N個數的序列,每次刪除K個數,要求能刪除的次數最多,問你這個K個數是什麼?

思路:
最開始是考慮選擇出現最多的K個數,但看了樣例2 發現如果某個數出現次數很多,那麼選擇多次這個數會更好。所以要把每個數能貢獻的次數考慮進去。我的做法是二分最小的出現次數,使得這最小出現次數儘量大。check函數是判斷當前這個最小次數v能否籌夠K 個數,每個數能貢獻的是 出現次數/v,因爲每個數可以被放進多個。

具體代碼 如下:

#include<bits/stdc++.h>

using namespace std;
const int MAX = 2e5+10;
typedef long long ll;
int s;
int N,K;
int book[MAX];
vector<int> vec[MAX];//該出現次數有哪些數。
void init(){
    for(int i=1;i<=(int)2e5;++i){
        if(book[i] != 0){
            vec[book[i]].push_back(i);
        }
    }
}
bool check(int v){
    ll sum = 0;
    for(ll i=v;i<=N;++i){
        sum += i/v*(int)vec[i].size();
        //對於該出現次數,貢獻出現次數/v*(個數)
    }
    if(sum >= K)    return true;
    else    return false;
}
int main(void){
    scanf("%d%d",&N,&K);
    for(int i=1;i<=N;++i){
        scanf("%d",&s);
        book[s]++;
    }
    init();
    int l = 1,r = N;
    while(r - l > 1){
        int mid = (l+r)/2;
        if(check(mid))
            l = mid;
        else
            r = mid;
    }
    if(check(r))    l = r;
    vector<int> res;
    for(int i=l;i<=N;++i){
        int Time = i/l;//Time表示這個數應該被放入多少次。
        //把高於該出現次數的數都放進去即可。
        for(int j=0;j<vec[i].size();++j){
            for(int k=0;k<Time;++k){
                res.push_back(vec[i][j]);
            }
        }
    }
    for(int i=0;i<K;++i){
        printf("%d",res[i]);
        if(i != K-1)
            printf(" ");
        else
            printf("\n");
    }
    return 0;
}

E題
題意:相當求的次數序列,比如1 1 3 3 5 5 5 次數序列就是2 2 3,即數的出現次數。從中可以得到的序列
x,2x,4x,符合每一個數是前面的二倍,
這裏每個數可以由比本身大的數組成,比如4,可以由比4大的數。問你最大的該序列和是多少。似乎有點亂。。。具體讀題吧。

做法是,直接枚舉x即可。把所有次數放到multiset裏面,判斷比2x大的次數是否具有,如果有就繼續判斷4x直到停止。
x從1枚舉到N即可。因爲每次判斷最多是log級,所以總的時間複雜度也就O(Nlog2(N));

代碼如下:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
map<int,int> mp;
multiset<int> st;
int N,x;
int main(void){
    scanf("%d",&N);
    for(int i=1;i<=N;++i){
       scanf("%d",&x);
       mp[x]++;
    }
    for(map<int,int>::iterator it = mp.begin();it != mp.end();++it){
        st.insert(it->second);
    }
    ll res = 0;
    for(int i=1;i<=N;++i){
        int now = i;
        ll temp = 0;
        multiset<int>::iterator it = st.lower_bound(now);
        while(true){
            if(it == st.end())  break;
            temp += now;
            now *= 2;
            if(*it >= now)  it++;
            else    it = st.lower_bound(now);
        }
        res = max(res,temp);
    }
    printf("%lld\n",res);

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章