【Codeforces Round #765 (Div. 2)】A、B、C

A - Ancient Civilization

题意:略。
题解:
统计每一个位置的0、1数量,选择大的那个即为最好的。

#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
const int maxn=1e3;
//int a[maxn],vis[100];
int a[35],b[35];
int main() {
		int t;cin>>t;
		while(t--){
			ll n,m,x;
			cin>>n>>m;
			memset(a,0,sizeof(a));
			memset(b,0,sizeof(b));
			while(n--){
				cin>>x;
				int now=0;
				while(x){
					if(x%2==0) a[now++]++;
					else b[now++]++;
					x/=2;
				}
				for(int i=now;i<m;i++)a[i]++;//别忘了这个,在这里wa了
			}
			ll k=1;
			ll sum=0;
			for(int i=0;i<35;i++){
				if(b[i]>a[i])sum+=k;
				k*=2;
			}
			cout<<sum<<endl;
		}
		

	return 0;
}

B. Elementary Particles

题意:
找到最长相同长度子段,使其满足存在相同位置的值相等。

题解:
对于每次找到相同的值,可以得到字段的最长长度为,相对较前的前面所有数可以计入,相对较后的后面所有数需要计入,还有该位置+1。
对每次出现相同的进行计算,记录最大值。
借助了a数组进行记录,每次循环都需要清楚原本留下的数值,所以复杂度为O(n·m),大概是1e9的级别,2s足够处理。

#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
const int maxn=1e5+5e4+3;
//int a[maxn],vis[100];
int a[maxn];

int main() {
	int t;cin>>t;

	while(t--){
		int n;cin>>n;
		int x;	int mmax=INT_MIN;
		memset(a,0,sizeof(a));
		for(int i=1;i<=n;i++){
			cin>>x;
			if(a[x]!=0)mmax=max(mmax,a[x]+n-i);
			a[x]=i;
		}
		if(mmax==INT_MIN)pr("-1\n");
		else pr("%d\n",mmax);
	}
	return 0;
}

C. Road Optimization

题意:
给出n个节点。
从i出发的速度按i处的值算。
d记录位置,a记录允许速度。
要求求出最多删去k个节点的全程最小长度。

题解:
o(n3)的dp[i][j],i指当前位置,j指余下了多少节点。
状态转移方程:
dp[i][k]=min(dp[i][k],dp[j][k-1]+a[j]*(d[i]-d[j]));
具体请结合代码注释理解。
注意
dp[1][0]=0——起点不能删去,其它为无穷大
d[n+1]=l——终点为l。

还是有点没弄明白贪心的不对,局部最优不代表全部最优?但是暂时想象不出来反例。

#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
const int maxn=1e3;
//int a[maxn],vis[100];
int a[maxn],d[maxn];
int dp[maxn][maxn];
int main() {
		int n,l,k0;cin>>n>>l>>k0;
		for(int i=1;i<=n;i++)cin>>d[i];
		for(int i=1;i<=n;i++)cin>>a[i];
		d[n+1]=l;
		for(int i=0;i<=n+1;i++)
		  for(int j=0;j<=n+1;j++)dp[i][j]=1e9;
		dp[1][0]=0;
		for(int i=1;i<=n+1;i++)//第i个 
		  for(int j=1;j<i;j++)//从j到i位置除去 
		    for(int k=1;k<=j;k++)//保留了k个 
		       dp[i][k]=min(dp[i][k],dp[j][k-1]+a[j]*(d[i]-d[j]));
	   int ans=1e9;
	   for(int i=0;i<=k0;i++)//找出删去的最小值,即查找保留的为:n-
	                         //i
	   ans=min(ans,dp[n+1][n-i]);
	   pr("%d\n",ans);

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值