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