Codeforces Round #765 (Div. 2)A-C题解

212 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。


A. Ancient Civilization

一堆数,让你求出某个数使这个数和这一堆数每个数的二进制位的差异位数的和最小

我们按位来看,统计每一位上1和0的个数,如果1的个数大于0的个数,那么该位选择1,否则选择0

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;

void solve()
{
	int n,k;
	cin>>n>>k;
	
	vector<int> cnt0(k+1),cnt1(k+1);
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		for(int j=k;j>=1;j--)
		{
			if(x&1) cnt1[j]++;
			else cnt0[j]++;
			x >>= 1;
		}
	}	
	int res = 0;
	for(int i=1;i<=k;i++)
		res = res * 2 + (cnt1[i] > cnt0[i]);
	cout<<res<<endl;
}

int main()
{
	int t;
	cin>>t;
	while(t--) solve();
	return 0;
}

B. Elementary Particles

给定一个数组,让你选择长度相等的两个子数组,需要保证两个子数组中至少有一位是相等的,求最长子数组的长度

抓住子数组有一位相等这个关键点,得到数组中需要有至少两个相同的数字。

  • 没有相同的数字,那么必然不存在这样两个子数组

  • 存在相同的数字时: 假设两个相同数字的位置分别为xy,且x<yx<yxy位置上的数字对齐

...a(x) ...
...a(y) ...

影响子数组相同元素后面长度的是y的大小,长度为nyn-y

影响子数组下相同元素前面长度的是x的大小,长度为x1x-1

最后加上相同元素的长度1

最后len=ny+x1+1=n+xylen = n-y+x-1+1=n+x-y

求最大值,即求xyx-y最大值,x<yx<y,那么就是找最近的两个相同数字

下面代码是将每个数字出现的下标存进数组,最后排序,然后找最大值。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;

vector<int>p[150001];

void solve()
{
	for(int i=1;i<=150000;i++)
		p[i].clear();
	int n;
	cin>>n;
	for(int i=1;i<=n;i++) 
	{
		int x;
		cin>>x;
		p[x].push_back(i);
	}
	int mx = -1e9;
	for(int i=1;i<=150000;i++)
	{
		if(p[i].size()<=1) continue;
		sort(p[i].begin(),p[i].end());
		for(int j=0;j<p[i].size()-1;j++)
			mx = max(mx,p[i][j] - p[i][j+1]);
	}
	if(mx==-1e9) cout<<-1<<endl;
	else cout<<n + mx<<endl;
}

int main()
{
	int t;
	cin>>t;
	while(t--) solve();
	return 0;
}

C. Road Optimization

长度为e的一段路,有n个限速牌,did_i个牌子上有个数字aia_i,代表后面的路每走一千米耗时aia_i分钟,现可以移除除第一个牌子以外最多k个牌子,求最短时长

n个牌子,移除最多k个,求最优问题,根据经验做法为DP

  • 状态表示:

f[i][j]f[i][j]代表前i个牌子来说,移除了j个牌子的最短时间

  • 状态转移:

状态转移的时候,我们还要再枚举一个变量pos,代表的是我们移除[pos+1,i1][pos+1,i-1]之间的所有牌子(共ipos1i-pos-1个),只有这样才能计算最短时间。那么这段移除牌子路程的时间为b[pos](a[i]a[pos])b[pos]*(a[i]-a[pos])

f[i][j]=min(f[i][j],f[pos][j(ipos1)]+b[pos](a[i]a[pos]))f[i][j] = min(f[i][j],f[pos][j-(i-pos-1)]+b[pos]*(a[i]-a[pos]))

pos:在i位置左边的牌子的位置,每到一个i值,都是枚举i左边的pos

初始化: f[0][0]=0f[0][0] = 0 当一个牌子不移除时:f[i][0]=f[i1][0]+b[i1](a[i]a[i1])f[i][0] = f[i-1][0] + b[i-1] * (a[i] - a[i-1])

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;

int f[505][505];
int a[505],b[505];

void solve()
{
	int n,e,k;
	cin>>n>>e>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	a[n+1] = e;
	memset(f,0x3f,sizeof f);
	f[0][0] = 0;
	for(int i=1;i<=n+1;i++)
		f[i][0] = f[i-1][0] + b[i-1] * (a[i] - a[i-1]);
	
	int res = 1e9;
	for(int i=2;i<=n+1;i++)
		for(int j=0;j<=k;j++)
			for(int pos=1;pos<i;pos++)
			{
				if(i-pos-1<=j) f[i][j] = min(f[i][j],f[pos][j-(i-pos-1)]+b[pos]*(a[i]-a[pos]));
				if(i==n+1) res = min(res,f[i][j]);
			}
	cout<<res<<endl;
}

int main()
{
	int t;
//	cin>>t;
	t = 1;
	while(t--) solve();
	return 0;
}