Codeforces Round #809 (Div. 2)(A~D2)

A. Another String Minimization Problem

给出长度为m的全部为B组成的字符串,给出长度为n的数组a,进行n次操作,第i次可以将a[i]位置的B换成A,也可以将m+1-a[i]处的B换为A,求经过n此操作后字典序最小的字符串。

思路:暴力,每次替换比较靠前的B,但是若是被替换过了,那就替换靠后的那个。

AC Code:

#include <bits/stdc++.h>

const int N=55;
int t,n,m;
int a[N];
char s[N];
bool vis[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>>m;
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
		}
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=m;i++){
			s[i]='B';
		}
		for(int i=1;i<=n;i++){
			int pos1=a[i];
			int pos2=m+1-a[i];
			int min=std::min(pos1,pos2);
			if(vis[min]) s[pos1+pos2-min]='A',vis[pos1+pos2-min]=1;
			else s[min]='A',vis[min]=1;
		}
		for(int i=1;i<=m;i++){
			std::cout<<s[i];
		}
		std::cout<<'\n';
	}
	return 0;
}

 B. Making Towers

给出一个颜色序列,第一个放在(0,0)处,接下来的只能放在前一个的上,左,右方向,问对于每一个颜色,最大排成的高度是多少。就是相连的在y轴上的最大距离,例如:

红色的最大高度为3。

思路:很显然,当同一个色块之间相距的色块是偶数个时,是可以摞起来的。所以直接用STL的map套vector即可,O(n)的时间复杂度,可以过。

AC Code:

#include <bits/stdc++.h>

const int N=1e5+5;
int t,n,m;
int a[N],ans[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=0;i<=n+1;i++) ans[i]=0;
		std::map<int,std::vector<int>>mp;
		for(int i=1;i<=n;i++){
			std::cin>>a[i];
			mp[a[i]].push_back(i);
		}
		for(auto u:mp){
			int len=u.second.size();
			if(len==1){
				ans[u.first]=1;
				continue;
			}
			if(!len) continue;
			int cnt=0,aa=0,last=u.second[0];
			for(int i=1;i<len;i++){
				if((u.second[i]-last)%2) cnt++,last=u.second[i];
				if(i==len-1) aa=std::max(aa,cnt);
			}
			ans[u.first]=aa+1;
		}
		for(int i=1;i<=n;i++){
			std::cout<<ans[i]<<" \n"[i==n];
		}
	}
	return 0;
}

 os:看到有佬是DP写的,,,不会DP只会暴力呜呜呜

C. Qpwoeirut And The City

定义一个建筑是cool的,即它的高度高于相邻两个建筑的高度。给出连续的建筑物高度,可以增高某些建筑物,现最大化cool建筑的数量,求最少需要加高的高度之和。

思路:对于奇数个连续建筑物高度,一定是隔一个是cool的,方案一定,直接求和即可;对于偶数个连续建筑物高度,想要最大化cool的数量,一定是连续偶数位置是cool建筑,再连续的奇数位置的是cool建筑,可以利用前缀和,分别求出偶数位置是cool时所需增加的最少高度和,奇数位置是cool时所需增加的最少高度和,扫一遍寻找这个断点,即奇偶分界点即可,找到最小的花费。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N=1e5+5;
int t,n;
int a[N];
ll odd[N],even[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];
		}
		for(int i=2;i<n;i++){
			odd[i]=odd[i-1],even[i]=even[i-1];
			if(i&1) odd[i]+=std::max({a[i-1]+1-a[i],a[i+1]+1-a[i],0});
			else even[i]+=std::max({a[i-1]+1-a[i],a[i+1]+1-a[i],0});
		}
		if(n&1){
			std::cout<<even[n-1]<<'\n';
			continue;
		}
		ll res=std::min(odd[n-1],even[n-1]);
		for(int i=2;i<n-2;i+=2){
			res=std::min(even[i]+odd[n-1]-odd[i+1],res);
		}
		std::cout<<res<<'\n';
	}
	return 0;
}

D1/D2. Chopping Carrots

D1和D2就只有数据范围不同,直接放hard version,对于easy version一样适用。

给出a数组和k,数组p的范围是大于等于1,小于等于k,求最小的题中公式。

思路:学习大佬的思路。对于每一个a[i],虽然p[i]有k个,但是\left \lfloor \frac{a_{i}}{p_{i}} \right \rfloor的取值不会很多,由整除分块的思想,取值的数量是根下a[i]级别的,所以我们用类似整数分块的思路枚举\left \lfloor \frac{a_{i}}{p_{i}} \right \rfloor的取值。可用数组max表示\left \lfloor \frac{a_{i}}{p_{i}} \right \rfloor最小值为i时所有\left \lfloor \frac{a_{i}}{p_{i}} \right \rfloor最大值。对于每个a[i],我们都枚举它的取值x,并记录上一次的取值,就可以用上一次的取值更新max[x+1],因为在整除分块的枚举中x的取值一定是递减的。最后扫描一遍更新答案即可。 

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
#define INF 0x3f3f3f3f
const int N=1e5+5;
const int mod=1e9+7;
int t,n,k;
int a[N],max[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>>k;
        memset(max,0,sizeof(max));
        for(int i=1;i<=n;i++){
            std::cin>>a[i];
            int x=INF;
            for(int l=1,r;l<=std::min(k,a[i]);l=r+1){
                int t=a[i]/l;
                r=a[i]/t;
                max[t+1]=std::max(max[t+1],x);
                x=t;
            }
            max[0]=std::max(max[0],x);
        }
        int ans=INF,maxn=0;
        for(int i=0;i<=a[1];i++){
            maxn=std::max(maxn,max[i]);
            ans=std::min(ans,maxn-i);
        }
        std::cout<<ans<<'\n';
    }
    return 0;
}

若有错误请指教,谢谢!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值