2022牛客OI赛前集训营-普及组(第二场)

A:隔离

qwq题目看错了。


 

题目描述

鸡尾酒要从 A 地去 B 地办 n 件事,其中第 iii 件事耗时 ai分钟,办完之后回到 A 地。但是如果他在 B 地连续待的时间大于等于 240 分钟,那么行程卡中就会显示他去过 B 地。根据 A 地的防控政策,如果去过 B 地,那么就会被隔离 7 天(10080 分钟),隔离之后才能继续正常行动(例如再启程去B 地,或者在 A 地开始正常生活)。于是他有一个对策,即在 240 分钟快到的时候就从 B 地回到 A 地,然后再去 B 地,这样 240 分钟就会重新计时,从 A 地往返一趟 B 地耗时 400 分钟。现在他在 A 地准备出发,想要在 B 地办完所有事,回 A 地开始正常生活,办 n 件事的顺序无法打乱,且办每一件事的过程中无法打断。请问他至少需要多少分钟?

输入描述:

第一行包含一个正整数 n,表示事情的个数。

接下来包含 n 个正整数,表示办每一件事所需要消耗的时间 ai。

输出描述:

输出一行一个数字表示答案。

示例1

输入

1
240

输出

10720

说明

去过 B 地的时间大于等于 240 分钟就会被隔离,所以鸡尾酒会被隔离 7 天,隔离后才能进行正常生活。所以总耗时为 400 + 240 + 10080(其中 400 是来回 B 地的时间)。注意不能将 240 分钟的事情拆解成两次来办,因为办一件事的过程不能被打断。

示例2

输入

2
120 121

输出

1041

说明

往返一次办第一件事,再往返一次办第二件事。共耗时 400+120+400+121=1041

备注:

对于 20% 的数据,有 n=1

对于 40% 的数据,有 1≤n≤2

对于另外 10% 的数据,有 240≤ai

对于 100% 的数据,有 1≤n,ai≤1000

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1010;
int a[N],n;
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        sum+=a[i];
    }
    int cnt=1;
    int ans=0;
    bool flag=false;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>=240)
        {
            flag=true;
            break;
        }
        if(a[i]+ans>=240)
        {
            ans=a[i];
            cnt++;
        }
        else
        {
            ans+=a[i];
        }
    }
    if(flag)
    {
        cout<<10080+400+sum<<"\n";
    }
    else
    {
        cout<<min((int)(10080+400+sum),cnt*400+sum)<<"\n";
    }
    return 0;
}

给定三个正整数 M,N,k,对于一个正整数 x,云浅认为它是「好数」当且仅当

- M≤x≤N;
- x 在十进制下的所有位上的数字和为 k。

请你求出所有「好数」中,十进制下所有位上数字的积最大的那个。

你需要求出这个数并输出其十进制下所有位上数字的积。如果有多解,选尽可能小的 x。

数据保证有解。

输入描述:

 
 

本题有多组数据。第一行一个正整数 TTT 表示数据组数。

接下来 T 行,每行三个正整数 M,N,k。

输出描述:

 
 

对于每组数据,一行两个正整数,以空格隔开,分别表示你求出的 x 以及其十进制下所有位上数字的积。
 

示例1

输入

1
114514 191981 10

输出

121222 16

说明

取 x=121222,则其数字和为 1+2+1+2+2+2=10,数字积为 1×2×1×2×2×2=16。

备注:

 
 

对于 100% 的数据,1≤M≤N≤5×10^6,1≤k≤100,1≤T≤100。

不得不说,这题数据是有问题

明明得到1e7,5e6就可以过,  而且1e7就炸内存,交不上。。。。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define PII pair<int,int>
const int N=5e6+10;
int sum[N],ji[N];
vector<PII>G[110];
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    sum[0]=0;
    ji[0]=1;
    for(int i=1;i<=5e6;i++)
    {
        sum[i]=sum[i/10]+i%10;
        ji[i]=ji[i/10]*(i%10);
        G[sum[i]].pb({i,ji[i]});
    }
   
    int T;
    cin>>T;
    while(T--)
    {
       int m,n,k;
       cin>>m>>n>>k;
       int f1=-1,f2=-1;
       for(int i=0;i<G[k].size();i++)
       {
           int  s1=G[k][i].first;
           int  s2=G[k][i].second;
           if(s1>n||s1<m)continue;
           if(s2>f2)
           {
               f2=s2;
               f1=s1;
           }
       }
       cout<<f1<<" "<<f2<<"\n";
    }
    return 0;
}

C:电梯停靠

题目描述

有一个 n 层高的楼,电梯会在 1∼n层之间运行。每次运行结束后,电梯都会自动停靠在 x 层。假设一个人想从第 5 层到第 10 层,那么电梯会先从第 x 层(因为之前已经自动停靠在 x 层了)走到第 5 层,然后从第 5 层走到第 10 层,最后再从第 10 层回到自动停靠的楼层 x 层。电梯总共会行走 ∣x−5∣+∣5−10∣+∣10−x∣ 的距离(其中 ∣x∣ 表示 x 的绝对值)

现在已知 m 个人依次乘坐电梯,每个人都会在电梯自动停靠在 x 层之后才乘坐。第 i 个人乘坐电梯是从 ai 层移动到 bi​ 层。现在 x 由你设置,你需要让电梯的总行走距离最短。请你输出对应的 x 和最短的行走距离。若有多个可能的 x,输出最小的一个。

输入描述:

第一行包含两个正整数 n,m表示楼的层数和乘坐电梯的人数。

接下来包含 m 行,每行给出两个数字 ai,bi(ai<bi),意义如题面所示。

输出描述:

输出两个数字,第一个数字表示电梯自动停靠的楼层,第二个数字表示电梯行走的最短距离。

示例1

输入

10 2
3 7
4 6

输出

4 12

说明

电梯一开始自动停靠在位置 4,第一个人想要从第 3 层走到第 7 层。则电梯共行走 |4-3|+|3-7|+|7-4|=8。第二个人想要从第 4 层行走到第 6 层,行走之后电梯停靠回第四层,电梯共行走 8 + |4-6|+|6-4|=12。

若电梯自动停靠在 5 或 6,则总行走距离也是 12,但是对于多个可能的 x,应该输出最小值。

示例2

输入

15 4
3 7
2 6
10 13
1 5

输出

5 40

示例3

输入

15 7
1 2
1 2
1 2
8 9
10 11
12 13
14 15

输出

8 74

备注:

对于 20% 的数据,有 1≤n,m≤100

对于 50% 的数据,有 1≤n,m≤2000

对于另外 20% 的数据,对于任意的 i(1≤i<m) 有 ai<bi<a(i+1)<b(i+1)

对于 100% 的数据,有 1≤n,m≤5∗10^5,1≤a,b≤n

这题更离谱,我乱搞过了。。。

正解下午补一下,这里贴一份我赛场代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e5+10;
int x[N],y[N],p[2*N];
int n,m,cnt;
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
   // freopen("T3simple.in","r",stdin);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>x[i]>>y[i];
        p[++cnt]=x[i];
        p[++cnt]=y[i];
    }
    sort(p+1,p+1+cnt);
    int sum1=0,sum2=0;
    int f1=p[cnt/2];
    int f2=p[cnt/2+1];
    //1
    for(int i=1;i<=m;i++)
    {
        sum1+=abs(f1-x[i])+abs(x[i]-y[i])+abs(y[i]-f1);
    }
    //2
    for(int i=1;i<=m;i++)
    {
        sum2+=abs(f2-x[i])+abs(x[i]-y[i])+abs(y[i]-f2);
    }
    if(sum1<=sum2)
    {
        cout<<f1<<" "<<sum1<<"\n";
    }
    else
    {
        cout<<f2<<" "<<sum2<<"\n";
    }

    return 0;
}

正解:差分

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+10;
int pre[N],pre1[N],suf[N],suf1[N];
int pos=-1,ans=1e18;
int n,m,a,b,sum;
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b;
        pre[a-1]+=2;
        suf[b+1]+=2;
        sum+=(b-a)*2;
    }
    for(int i=n;i>=1;i--)
    {
        pre[i]+=pre[i+1];
        pre1[i]=pre1[i+1]+pre[i];
    }
    for(int i=1;i<=n;i++)
    {
        suf[i]+=suf[i-1];
        suf1[i]=suf1[i-1]+suf[i];
        if(suf1[i]+pre1[i]<ans)
        {
            pos=i;
            ans=suf1[i]+pre1[i];
        }
    }
    cout<<pos<<" "<<ans+sum<<"\n";
    return 0;
}

 D:

题目描述

给定 n 个数字,第 i 个数字的大小为 ai,且它属于第 bi个集合里。在一个集合中选择一个数字,得到的价值是这个数字的大小,选择多个数字,得到的价值是这些数字的异或和。

你得到的总价值是所有集合的价值之和。你至多从中选择 m(m≤n)个数字,使得这些数字的总价值最大。

输入描述:

第一行输入两个正整数 n,m(1≤n,m≤2000)n

接下来 nnn 行,每行给出两个正整数 ai,bi(1≤ai,bi≤2000)a,分别表示第 i 个数字的大小和所属集合的编号。

输出描述:

输出一行一个整数表示答案

示例1

输入

3 3
7 1
6 1
3 1

输出

7

说明

由于三个数字都在第一个集合,如果选择 6 和 7,则获得的价值为7 异或 6 = 1。只选一个数字 7 是最优的方案。

示例2

输入

3 3
7 1
6 3
3 1

输出

13

说明

对于 1 号集合,只选一个数字 7 是最优的方案,对于 3 号集合,选择一个 6。得到的总价值为 6+7=13

示例3

输入

5 3
6 1
5 1
2 1
3 3
2 3

输出

10

分组背包板子题

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define int long long
const int N=2e3+10;
const int M=2e3+5;
int n,m,dp[N][N],num[N][N],dpp[N],zz[N]; //dp[i][j]表示看到第i个数,异或出j至少所需要的数字个数,num[i][j]表示第i组j个数最大的异或值
vector<int>ve[N];
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        int x,y;
        cin>>x>>y;
        ve[y].pb(x);
        zz[y]++;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=M;j++)
        {
            dp[i][j]=1e9;
        }
    }
    for(int zu=1;zu<=2000;zu++)
    {
        if(zz[zu]!=0)   dp[1][ve[zu][0]]=1;  //不加判断的话会访问越界导致运行崩溃
        for(int i=2;i<=zz[zu];i++)
        {
            dp[i][ve[zu][i-1]]=1;  //这一步很重要,不要忘记
            for(int j=1;j<=M;j++)
            {
                if(dp[i-1][j]!=1e9)
                {
                    dp[i][j]=min(dp[i][j],dp[i-1][j]);
                    dp[i][j^ve[zu][i-1]] = min(dp[i-1][j]+1,dp[i][j^ve[zu][i-1]]);
                }
            }
        }
        for(int j=1;j<=M;j++)
        {
            if(dp[zz[zu]][j]!=1e9)  num[zu][dp[zz[zu]][j]]=max(num[zu][dp[zz[zu]][j]],j);
        }
        for(int i=1;i<=zz[zu];i++)
        {
            for(int j=1;j<=M;j++)
            {
                dp[i][j]=1e9;
            }
        }
    }
    for(int i=1;i<=2000;i++)
    {
        for(int j=m;j>=0;j--)
        {
            for(int k=1;k<=zz[i];k++) // 最后的枚举,只枚举到本组的个数
            {
                if(j>=k)  dpp[j]=max(dpp[j],dpp[j-k]+num[i][k]);
            }
        }
    }
    cout<<dpp[m]<<"\n";
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值