2019-2020 ICPC, NERC, Southern and Volga Russian Regional Contest

A.Berstagram

题意:起始数列是1,2,3,……,n,给你m个操作x,表示将数字x和前一个位置的数交换,如果已经在第一个则不做操作,求每个数能到达的位置的最大和最小值;

分析:扫一遍模拟,更新左右极限;

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
int a[maxn],pos[maxn],l[maxn],r[maxn];
int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) a[i]=l[i]=r[i]=i,pos[i]=i;
    for(int i=1;i<=m;i++)
    {
        int x;scanf("%d",&x);
        if(a[x]==1) continue;
        int s1=a[x];
        int y=pos[s1-1];
        a[x]--;a[y]++;
        l[x]=min(l[x],a[x]);r[x]=max(r[x],a[x]);
        l[y]=min(l[y],a[y]);r[y]=max(r[y],a[y]);
        swap(pos[s1],pos[s1-1]);
    }
    for(int i=1;i<=n;i++) printf("%d %d\n",l[i],r[i]);
    return 0;
}

B. The Feast and the Bus

题意:一辆巴士可以搭乘一整支或两整支队伍,费用是每一趟的最大承载人数*趟数,求最小费用;

分析:贪心+二分check;如果每次都只搭乘一支队伍,答案可以直接得到;每次可搭乘一支或两支时,按照每支队伍的人数排序,二分巴士的最大承载人数,贪心构造乘车的两支队伍,即就是当前的最大+最小,如果放不下那就是最大单独乘坐,因为最小还可以和次大构造;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=8007;
int num[maxn];
ll rua()
{
    int n,k,x,cnt=0;scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%d",&x),num[x]++;
    sort(num+1,num+1+k);
    int mx=0;
    for(int i=1;i+i<=k;i++) mx=max(mx,num[i]+num[k-i+1]);
    if(k&1) mx=max(mx,num[k/2+1]);
    ll ans=(ll)1e18;
    for(int i=num[k];i<=mx;i++)
    {
        int l=1,r=k,tmp=0;
        while(l<=r)
        {
            tmp++;
            if(l!=r && num[l]+num[r]<=i) l++,r--;
            else r--;
        }
        ans=min(ans,1ll*tmp*i);
    } 
    return ans;
}
int main()
{
    printf("%lld\n",rua());
    return 0;
}

F. Data Center

题意:给你一个矩形面积,求最小周长(整数)

分析:这种都不会干脆别打ACM了

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,ans=(int)1e9;scanf("%d",&n);
    for(int i=1;i*i<=n;i++) if(n%i==0) ans=min(ans,i+n/i);
    printf("%d\n",ans+ans);
}

H. Happy Birthday

题意:给你0~9这10个数字的个数,求不能构造的数中的最小值;

分析:分类讨论;非零数的个数为0时,答案是他本身;按照个数升序+数值升序排序,个数最少的数非零时,答案时个数+1个它本身,否则继续分类:0的个数最小时,如果还有跟他个数相同的x,答案时个数+1个x;否则就是1+(个数+1)个0;

#include<bits/stdc++.h>
using namespace std;
int cnt[15];
struct node{int num,x;} p[15];
bool cmp(node a,node b) {return a.num==b.num?(a.x<b.x):(a.num<b.num);}
void rua()
{
    for(int i=0;i<=9;i++) scanf("%d",&p[i].num),p[i].x=i,cnt[i]=p[i].num;
    sort(p,p+10,cmp);
    for(int i=0;i<=9;i++)
        if(p[i].num==0 && p[i].x>0) {printf("%d\n",p[i].x);return;}
    if(p[0].x==0) 
    {
        if(p[1].num==p[0].num)
        {
            while(p[1].num--) printf("%d",p[1].x);
            printf("%d\n",p[1].x);return;
        }
        printf("1");
        while(cnt[0]--) printf("0");
        printf("0\n");return;
    }
    while(p[0].num--) printf("%d",p[0].x);
    printf("%d\n",p[0].x);return;
}
int main()
{
    int t;scanf("%d",&t);
    while(t--) rua();
    return 0;
}

J. The Parade

题意:给出身高为1~n的人数,要求每一行的人身高差不超过1,并且每一行的人数相同,求最多多少人能进入方阵;

分析:贪心+二分check;二分每一行的人数,记下剩余的人数,如果身高+1的和剩余不能凑成一行,剩余的人就不要;

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
typedef long long ll;
ll a[maxn];
int n;
ll k;
bool check(ll mid)
{
    ll cnt=0,res=mid;
    for(int i=1;i<=n;i++)
    {
        ll x=a[i];
        if(x>=res) cnt++,x-=res;
        cnt+=x/mid;res=mid-x%mid;
        if(cnt>=k) return true;
    }
    return cnt>=k;
}
ll rua()
{
    ll sum=0;scanf("%d%lld",&n,&k);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i];
    ll l=1,r=sum/k,ans=0;
    while(l<=r)
    {
        ll mid=(l+r)>>1;
        if(check(mid)) ans=mid,l=mid+1;
        else r=mid-1;
    }
    return k*ans;
}
int main()
{
    int t;scanf("%d",&t);
    while(t--) printf("%lld\n",rua());
    return 0;
}

L. Divide The Students

题意:给出a b c三种人数的个数,把他们分成三组,a和c不能分在同一组,问三组人数中最大值的最小值是多少;

分析:贪心+二分check;二分答案,贪心的构造答案,看代码就好了;

#include<bits/stdc++.h>
using namespace std;
int a,b,c;
bool check(int x)
{
    if(a>x && c>x) return false;
    int a1=a,b1=b,c1=c;
    if(a1>x)
    {
        a1-=x;
        if(a1>x) return false;
        if((x-a1)+(x-c1)>=b1) return true;
        else return false;
    }
    else if(c1>x)
    {
        c1-=x;
        if(c1>x) return false;
        if((x-c1)+(x-a1)>=b1) return true;
        else return false;
    }
    else if((x-a1)+(x-c1)+x>=b1) return true;
    else return false;
}
void rua()
{
    scanf("%d%d%d",&a,&b,&c);
    int l=(a+b+c+2)/3,r=max({a,b,c}),ans;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ans);
}
int main()
{
    int t;scanf("%d",&t);
    while(t--) rua();
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值