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

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #765 (Div. 2)A-C题解相关的知识,希望对你有一定的参考价值。


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 < y x<y x<y
    xy位置上的数字对齐

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

    影响子数组相同元素后面长度的是y的大小,长度为 n − y n-y ny
    影响子数组下相同元素前面长度的是x的大小,长度为 x − 1 x-1 x1
    最后加上相同元素的长度1
    最后 l e n = n − y + x − 1 + 1 = n + x − y len = n-y+x-1+1=n+x-y len=ny+x1+1=n+xy
    求最大值,即求 x − y x-y xy最大值, x < y x<y x<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个限速牌, d i d_i di个牌子上有个数字 a i a_i ai,代表后面的路每走一千米耗时 a i a_i ai分钟,现可以移除除第一个牌子以外最多k个牌子,求最短时长

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

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

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

    f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ p o s ] [ j − ( i − p o s − 1 ) ] + b [ p o s ] ∗ ( a [ i ] − a [ p o s ] ) ) f[i][j] = min(f[i][j],f[pos][j-(i-pos-1)]+b[pos]*(a[i]-a[pos])) f[i][j]=min(f[i][j],f[pos][j(ipos1)]+b[pos](a[i]a[pos]))

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

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

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

往期优质文章推荐

领取大量学习资源

以上是关于Codeforces Round #765 (Div. 2)A-C题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #436 E. Fire(背包dp+输出路径)

codeforces 765F Souvenirs

[ACM]Codeforces Round #534 (Div. 2)

codeforces765F Souvenirs

Codeforces 765F Souvenirs - 莫队算法 - 链表

codeforces 765 F 线段树+set