Educational Codeforces Round 137 (Rated for Div. 2)(A~D)

A. Password(组合数)

给出0~9中用不到的数字,密码是由四位数字组成,其中每种数字有两个,问可能存在的密码种类数。

思路:在用到的数字中两两互组,对于两个数字组队而言,有6种排列方式,乘起来即可。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t,n;
int a[N];

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n;
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		ll ans=((9-n)+1)*(9-n)/2*6;
		std::cout<<ans<<'\n';
	}
	return 0;
}

B. Permutation Value(构造)

给出一个数字n,对于一个permutation,它的value是这个permutation中permutation的数量。对于每个n,构造一个value最小的permutation。

思路:正着放一半,倒着放一半即可,即对于5而言,可以是1 5 2 4 3。 

 AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t,n;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n;
		std::vector<int>ans;
		for(int i=1;i<=(n+1)/2;i++){
			ans.push_back(i);
			if((n+1)!=2*i)
				ans.push_back(n+1-i);
		}
		for(int i=0;i<n;i++){
			std::cout<<ans[i]<<" \n"[i==n-1];
		}
	}
	return 0;
}

os:有简单的方法。。直接把1移到n后面就可以,,这样显得我很呆欸

C. Save the Magazines(DP,思维)

给出一个数组和一个对应长度的字符串,如果某个位置对应字符为1,则加上该位置数组对应的值,现在对于每一个1来说,它们都可以最多向前移动一次,问经过若干次操作之后,能得到的最大价值之和是多少。

思路: (1)比较好想的DP。我们可以开两维数组,第一维表示遍历到的位置,第二维表示该位置的状态,对于该位置是1的时候,可以有两种转换方式,f[i][0]是表示该位置的1向前移位,就一种情况,就是前一位也是0的情况下可以完成;f[i][1]的时候表示该位置的1不移动,此时取前一位的较大值,即max(f[i-1][1],f[i-1][0])+a[i]。对于该位是0时,只能存在f[i][0]的情况,直接从前一位的较大值转移即可。

(2)贪心。对于一段连续的1,我们可以枚举对应范围内最适合放0的位置,就是a[i]值最小的位置,然后扫一遍非0的位置加入答案中。

AC Code:

(1)

#include <bits/stdc++.h>

typedef long long ll;
#define INF 0x3f3f3f3f
const int N=2e5+5;
int t,n;
std::string s;
int a[N];
ll f[N][2];

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n;
		std::cin>>s;
		s=' '+s;
		memset(f,0,sizeof(f));
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		for(int i=1;i<=n;i++){
			if(s[i]=='1'){
				f[i][1]=std::max(f[i-1][0],f[i-1][1])+a[i];
				f[i][0]=f[i-1][0]+a[i-1];
			}
			else f[i][0]=std::max(f[i-1][0],f[i-1][1]);
		}
		std::cout<<std::max(f[n][1],f[n][0])<<'\n';
	}
	return 0;
}

(2)

#include <bits/stdc++.h>

typedef long long ll;
#define INF 0x3f3f3f3f
const int N=2e5+5;
int t,n;
std::string s;
int a[N];

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>t;
	while(t--){
		std::cin>>n;
		std::cin>>s;
		s=' '+s;
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		int j=-1;
		for(int i=1;i<=n;i++){
			if(s[i]=='0') j=i;
			else if(j!=-1&&a[j]>a[i]){
				std::swap(s[i],s[j]);
				j=i;
			}
		}
		ll ans=0;
		for(int i=1;i<=n;i++){
			if(s[i]=='1')
				ans+=a[i];
		}
		std::cout<<ans<<'\n';
	}
	return 0;
}

os:方法二我一开始用双指针写挂了。。。学习了jls的代码,感觉非常妙

D. Problem with Random Tests(暴力枚举,复杂度分析)

 给出一个长度为n的01串,选择它的两个子串,使得它们所表示的十进制数的或值最大,输出这个最大的或值。

思路:显然,两个字符串中必定有一个是原字符串,因为原字符串表示的一定是子串中最大的数;对于答案,我们尽可能选择子串,令第一个1之后的最高位0变成1,因为如果某一位对于0有作用,必须选择的子串要大于等于最高位0的位数,所以字符串的开头一定位于最高位0到第一个1之间,暴力即可,至于暴力复杂度能过的原因,是因为01完全随机出现,全为50%的出现概率,所以直接暴力枚举复杂度能过。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
#define INF 0x3f3f3f3f
const int N=2e5+5;
int n;
std::string s;

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	std::cin>>n>>s;
	if(s.find('1')==std::string::npos){
		std::cout<<0<<'\n';
		return 0;
	}
	int a=s.find('1');
	if(s.substr(a).find('0')==std::string::npos){
		std::cout<<s.substr(a)<<'\n';
		return 0;
	}
	int b=a+s.substr(a).find('0');
	auto ans=s;
	for(int i=0;i<=b-a;i++){
		auto res=s;
		for(int j=0;j+i<n;j++){
			res[j+i]|=s[j];
		}
		ans=std::max(ans,res);
	}
	ans=ans.substr(ans.find('1'));
	std::cout<<ans<<'\n';
	return 0;
}

补不动辣!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值