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;
}