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

终榜:

我和我的队友,由于我开的新号, 帮我的队友试错于是D1分低了点

A:

题目大意:

一开始有一个长度为m的字符串,里面的元素全部为字符A

给定n,m分别表示操作次数和字符串长度

每次操作给定一个下标i,每次可以将第i个元素和第m-i+1个元素修改为B

求最终能得到的字典序最小的字符串

思路:签到题,模拟即可

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define T()\
	int tt; \
	cin>>tt; \
	while(tt--)
#define endl "\n"
const int N=2e6+10;
map<int,int>q;
int main()
{
    T()
    {
        q.clear();
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            x=min(x,m-x+1);//先取小的下标
            if(q.count(x))q[m-x+1]++;//如果小的下标已经变为B了,就将大的下标变为B
            else q[x]++;
        }
        for(int i=1;i<=m;i++)
        {
            if(q.count(i))cout<<'A';
            else cout<<'B';
        }
        puts("");
    }
}

B:

题目大意:

 按顺序给定n个方块,每个方块都有一个编号1~n,第一个方块放在坐标为(0,0)的点,后面的每个方块可以放在上一个方块的左方,右方,上方,但不能放在下方,现在要求输出n个数,为每种编号的方块最多可以连续放置多少个,注意这里答案互不影响,比如我可以先找出一个编号为1的最优解,在返回寻找编号为2的最优解

思路:仔细观察对于相同的编号,当他们之间的间隔为偶数时我们可以将它们叠起来,即连续放置起来,此时他们下标的奇偶性是不同的,开两个map,q1,q2于是可以有以下转换

if(i&1)q1[x]=q2[x]+1;//如果下标是奇数

else q2[x]=q1[x]+1;

x表示编号,i表示下标

最终打印更大的那个即可

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define T()\
	int tt; \
	cin>>tt; \
	while(tt--)
#define endl "\n"
const int N=2e6+10;
map<int,int>q1,q2;
int main()
{
    T()
    {
        q1.clear();
        q2.clear();
        int n;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            if(i&1)q1[x]=q2[x]+1;//如果下标是奇数
            else q2[x]=q1[x]+1;
        }
        for(int i=1;i<=n;i++)
        {
            cout<<max(q1[i],q2[i])<<' ';
        }
        puts("");
    }
}

 

 

C:

题目大意:

有n个楼房,以及给定的n个高度

你可以将某些楼房增加任意高度使得对于1<i<n,h[i]>h[i-1]并且h[i]>h[i+1],每增加1高度产生1代价

现在需要你尽可能使这种楼房多,找到最小的代价

思路:

分别讨论n为奇数和偶数的情况

如果n为奇数

那么对于所有下标为偶数的位置,使得这个位置满足情况即可

如果n为偶数

我们先令所有下标为偶数的位置,使得这个位置满足情况,

比如当n为8时,1 x _ y _ z _ 8,x,y,z表示这个位置满足条件式,1表示首位,8表示末位

然后我们可以发现,一旦有某个位置是奇数位,那么所有后面的满足条件式的位置都为奇数

比如若x为奇数位,那么就会变成1 _ x _ y _ z 8,

若y为奇数位,那么就会变成1 x _  _ y _ z 8,

所以我们从后往前枚举每个位置为奇数位,计算代价寻找最小值即可

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define T()\
	int tt; \
	cin>>tt; \
	while(tt--)
#define endl "\n"
const int N=2e6+10;
ll a[N],b[N];
int main()
{
    T()
    {
        int n;
        cin>>n;
        int ct=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",a+i),b[i]=a[i];//一开始初始化b数组等于a数组
        }
        ll ans=0;
        for(int i=2;i<n;i++)
        {
            if(i%2==0)
            {
                if(a[i]>a[i-1]&&a[i]>a[i+1])continue;
                else
                {
                    ans+=max(a[i-1],a[i+1])+1-a[i];
                    a[i]=max(a[i-1],a[i+1])+1;
                }
            }
        }
        if(n&1)
        {
            cout<<ans<<endl;
            continue;
        }
        ll res=ans;
        for(int i=n-1;i>=2;i--)
        {
            if(i&1)
            {
                res-=a[i-1]-b[i-1];
                //当前位置为奇数位,那么前面一位的数肯定是偶数位,那么我们一定修改过
                //所以将花费还原
                a[i-1]=b[i-1];//将前面的偶数位还原为原来的数字
                if(!(a[i]>a[i-1]&&a[i]>a[i+1]))
                {
                    res+=max(a[i-1],a[i+1])+1-a[i];
                    a[i]=max(a[i-1],a[i+1])+1;
                }
                ans=min(ans,res);//每次都取小值
            }
        }
        cout<<ans<<endl;
    }
}

D1:

题目大意:

给定n,k以及n个数字a[ 1 ]~a[ n ]

现在要求找到一个p使得对于1<=i<=n找到一个mx = max(a[ i ] / p),mn = min(a[ i ] / p)

现要求使得mx-mn尽可能小,输出这个尽可能小的值

思路:

由于数据并不大,我们可以枚举最大值mx,然后使得每个a[ i ] / p尽可能靠近这个最大值mx而又不超过最大值即可

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define T()\
	int tt; \
	cin>>tt; \
	while(tt--)
#define endl "\n"
#define inf INT_MAX
const int N=3e3+10;
int a[N];
vector<int>q[N];
bool vis[N];
int main()
{
	#ifdef LOCAL
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	#endif
    int n,k,i,j;
    int now,ans,mn,mx,mn1,mx1,mn2,mx2,pos,x1,x2,x3;
    int sj;
    T()
    {
        sj=0;
        scanf("%d",&n);scanf("%d",&k);
        for(i=1;i<=n;i++)
        {
            scanf("%d",a+i);
            sj=max(sj,a[i]);
            for(j=k;j>=1;j--)q[i].push_back(a[i]/j),vis[a[i]/j]=true;
            //将每个a[i]/j,1<=j<=k可能的取值存起来,vis数组表示这个数出现过
        }
        if(n==1)
        {
            cout<<0<<endl;
            continue;
        }
        ans=inf;
        for(i=1;i<=sj;i++)
        {
            //i即为枚举的最大值mx
            if(!vis[i])continue;//如果这个数没出现过则跳过
            mx=i;
            mn=i;
            for(j=1;j<=n;j++)
            {
                if(i>=a[j])
                {
                    mn=min(mn,a[j]);continue;
                }
                pos=upper_bound(q[j].begin(),q[j].end(),i)-q[j].begin();
                if(pos==0)
                {
                    mx=max(mx,q[j][pos]);
                }
                else
                {
                    mn=min(mn,q[j][pos-1]);
                }
            }
            ans=min(ans,mx-mn);
            //更新最值
        }
        cout<<ans<<endl;
        for(i=1;i<=n;i++)q[i].clear();//每次记得清空
        for(int i=1;i<=sj;i++)vis[i]=0;//
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值