cf div2 558题解报告

第三次做cf,以后继续加油

A:

模拟,计算出0的左右两侧的个数和值,然后比较两侧个数的大小即可

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
#define MAX 100005
#define MOD 1e7
int ans[MAX*4];
long long l[MAX+5];
long long c[MAX+5];
int main(void)
{
	int n;cin >> n;
	for(int i = 1;i<=n;i++){
		int loc = 0,v = 0;
		scanf("%d%d",&loc,&v);
		ans[loc+MAX]=v;
	}
	int a = 0,b = 0;
	int s = 0,t = 0;
	long long sum = 0;
	for(int i = 0; i <= MAX*2;i++){
		if(ans[i]){
			if(i < MAX)a++,s+=ans[i],l[a]=s;
			else if(i > MAX)b++,t+=ans[i],c[b]=t;
			if(i == MAX) sum += ans[i];
		}
	}
	int m;
	m = min(a,b);
	if(a>m)sum+=l[a]-l[a-m-1];
	else sum+=l[a]-l[a-m];
	if(b>m)sum+=c[m+1];
	else sum+=c[m];
	cout << sum;
}

B:

用hash统计数列中每个数的个数,记录开始和末尾的位置,同时得出最大的个数

然后在个数为最大个数的数字中找数列最小的子数列

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
#define MAX 1000005
#define MOD 1e7
int ans[MAX];
int loc[MAX][2];
int main(void)
{
	int cnt = 0;
	int n;cin >> n;
	for(int i = 1;i<=n;i++){
		int t;scanf("%d",&t);
		if(!ans[t])loc[t][0]=i,loc[t][1]=i;
		else loc[t][1]=i;
		ans[t]++;
		cnt = max(cnt,ans[t]);
	}
	int a=0,b=MAX;
	for(int i=1;i<=MAX-1;i++){
		if(ans[i]==cnt){
			if(b-a>loc[i][1]-loc[i][0])a = loc[i][0],b = loc[i][1];
		}
	}
	cout << a << ' ' << b;
}

C:

n个数变成相同的数,*2和/2两种操作,最少的操作次数是多少?

*2和/2很容易想到要将数字转化为二进制

然后先找最高位相同的部分

如1010 ,10,100,101

相同的部分就是10

剩下的位置要么为0,要么为-1(不存在)

所以对于后面不相同的部分,从第一次出现1,之后的所有数字包括1全部都要变成-1

这样处理后就剩下0,-1了然后就是

找保留至第多少列时的sum最小

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 100005
int ans[MAX][35];
int mp[MAX][35];
int c[MAX],col[35];
int main(void){
	 int n;cin >> n;
	 int cnt = 0,sum = 0;
	 memset(ans,-1,sizeof ans);
	 for(int i = 1;i<=n;i++){
	 	int a;cin >> a;
	 	int t=a,p = 1;
	 	while(t){
	 		mp[i][p]=t%2;t/=2;
	 		p++;
	 		sum++;
	 	}
	 	c[i]=p-1;
	 	cnt = max(cnt,p-1);
	 	int q = 1;
		for(int j = p-1;j>=1;j--){
			ans[i][q]=mp[i][j],q++;
		}
	 }
	 int s = 0,v = 0;
	 for(int i = 1;i <= cnt;i++){
	 	int p = 1;
	 	for(int j = 1;j<n;j++){
	 		if(ans[j][i]==ans[j+1][i])p++;
	 	}
	 	if(p==n)s = i;
	 	else break;
	 }
	 for(int i = 1;i<=n;i++){
	 	int flag = 0;
	 	for(int j = s+1;j<=cnt;j++){
	 		if(flag == 1)ans[i][j]=-1;
	 		if(ans[i][j]==1){
	 			v+=c[i]-j+1;
	 			c[i]=j-1;
	 			flag = 1;
	 			ans[i][j]=-1;
	 		}
	 	}
	}
	int nmin = 10000000;
	for(int i = s+1;i <= cnt;i++){
		for(int j = 1;j <= n;j++)
			if(ans[j][i]==0)col[i]++;
		col[i]+=col[i-1];
	}
	for(int i = s;i <=cnt;i++)nmin=min(nmin,v+(i-s)*n-(col[i]-col[s])+(col[cnt]-col[i]));
	cout << nmin;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值