算法竞赛进阶指南0x08 总结练习(下)

数的进制转换

编写一个程序,可以实现将一个数字由一个进制转换为另一个进制。

这里有62个不同数位{0-9,A-Z,a-z}。

输入格式
第一行输入一个整数,代表接下来的行数。

接下来每一行都包含三个数字,首先是输入进制(十进制表示),然后是输出进制(十进制表示),最后是用输入进制表示的输入数字,数字之间用空格隔开。

输入进制和输出进制都在2到62的范围之内。

(在十进制下)A = 10,B = 11,…,Z = 35,a = 36,b = 37,…,z = 61 (0-9仍然表示0-9)。

输出格式
对于每一组进制转换,程序的输出都由三行构成。

第一行包含两个数字,首先是输入进制(十进制表示),然后是用输入进制表示的输入数字。

第二行包含两个数字,首先是输出进制(十进制表示),然后是用输出进制表示的输入数字。

第三行为空白行。

同一行内数字用空格隔开。

输入样例:
8
62 2 abcdefghiz
10 16 1234567890123456789012345678901234567890
16 35 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2
35 23 333YMHOUE8JPLT7OX6K9FYCQ8A
23 49 946B9AA02MI37E3D3MMJ4G7BL2F05
49 61 1VbDkSIMJL3JjRgAdlUfcaWj
61 5 dl9MDSWqwHjDnToKcsWE1S
5 10 42104444441001414401221302402201233340311104212022133030
输出样例:
62 abcdefghiz
2 11011100000100010111110010010110011111001001100011010010001

10 1234567890123456789012345678901234567890
16 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2

16 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2
35 333YMHOUE8JPLT7OX6K9FYCQ8A

35 333YMHOUE8JPLT7OX6K9FYCQ8A
23 946B9AA02MI37E3D3MMJ4G7BL2F05

23 946B9AA02MI37E3D3MMJ4G7BL2F05
49 1VbDkSIMJL3JjRgAdlUfcaWj

49 1VbDkSIMJL3JjRgAdlUfcaWj
61 dl9MDSWqwHjDnToKcsWE1S

61 dl9MDSWqwHjDnToKcsWE1S
5 42104444441001414401221302402201233340311104212022133030

5 42104444441001414401221302402201233340311104212022133030
10 1234567890123456789012345678901234567890

这是一道非常基础的进制转化题,A进制->B进制,但是要用高精度,一般思维是先A->10,然后10->B,但是这题的做法可以一步到位,A->B,回顾一下10->B进制,我们ans.push_back(a%B) a/=B,这是我们基于10进制的除法,那我们如果能实现a关于A进制的除法,我们是不是就能一步到位了呢?~ 。~,来看代码。

#include<iostream>
#include<string>
#include<algorithm>
#include<vector>

using namespace std;

inline int get(char ch)
{
    if(ch>='A'&&ch<='Z') return ch-'A'+10;
    else if(ch>='a'&&ch<='z') return ch-'a'+36;
    return ch-'0';
}

inline char out(int num)
{
    if(num<=9&&num>=0) return num+'0';
    else if(num>=10&&num<=35) return num-10+'A';
    else return num-36+'a';
}

int main(){

    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);

    int T;
    cin>>T;

    while(T--)
    {
        int a1,a2;
        string s1,s2;
        cin>>a1>>a2>>s1;
        vector<int> v;
        for(auto ch:s1)
            v.push_back(get(ch));
        
        reverse(v.begin(),v.end());
        while(v.size())
        {
            int t=0;
            for(int i=v.size()-1;i>=0;i--)
            {
                t=a1*t+v[i];
                v[i]=t/a2;
                t%=a2;
            }
            s2.push_back(out(t));
            while(v.size()&&v.back()==0) v.pop_back();
        }
        reverse(s2.begin(),s2.end());
        cout<<a1<<" "<<s1<<endl<<a2<<" "<<s2<<endl;
        puts("");
    }

    return 0;
}

耍杂技的牛

农民约翰的N头奶牛(编号为1…N)计划逃跑并加入马戏团,为此它们决定练习表演杂技。

奶牛们不是非常有创意,只提出了一个杂技表演:

叠罗汉,表演时,奶牛们站在彼此的身上,形成一个高高的垂直堆叠。

奶牛们正在试图找到自己在这个堆叠中应该所处的位置顺序。

这N头奶牛中的每一头都有着自己的重量Wi以及自己的强壮程度Si。

一头牛支撑不住的可能性取决于它头上所有牛的总重量(不包括它自己)减去它的身体强壮程度的值,现在称该数值为风险值,风险值越大,这只牛撑不住的可能性越高。

您的任务是确定奶牛的排序,使得所有奶牛的风险值中的最大值尽可能的小。

输入格式
第一行输入整数N,表示奶牛数量。

接下来N行,每行输入两个整数,表示牛的重量和强壮程度,第i行表示第i头牛的重量Wi以及它的强壮程度Si。

输出格式
输出一个整数,表示最大风险值的最小可能值。

数据范围
1≤N≤50000,
1≤Wi≤10,000,
1≤Si≤1,000,000,000
输入样例:
3
10 3
2 5
3 3
输出样例:
2

和那个国王游戏挺像的,我们按强壮+体重重的牛排个序就行了。

#include<iostream>
#include<cstring>
#include<algorithm>

#define ll long long
#define pll pair<ll,ll>

using namespace std;

const int N=50010;

pll cows[N];
int n;

bool CMP(const pll &a,const pll &b)
{
    return a.first+a.second<b.first+b.second;
}
int main(){
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    
    scanf("%d",&n);

    for(int i=1;i<=n;i++)
        scanf("%lld%lld",&cows[i].first,&cows[i].second);
    
    sort(cows+1,cows+n+1,CMP);
    ll temp=0;
    ll res=-100000000000;

    for(int i=1;i<=n;i++)
    {
        res=max(res,temp-cows[i].second);
        temp+=cows[i].first;
    }

    printf("%lld\n",res);
    

    return 0;
}

最大的和

给定一个包含整数的二维矩阵,子矩形是位于整个阵列内的任何大小为1 * 1或更大的连续子阵列。

矩形的总和是该矩形中所有元素的总和。

在这个问题中,具有最大和的子矩形被称为最大子矩形。

例如,下列数组:

0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
其最大子矩形为:

9 2
-4 1
-1 8
它拥有最大和15。

输入格式
输入中将包含一个N*N的整数数组。

第一行只输入一个整数N,表示方形二维数组的大小。

从第二行开始,输入由空格和换行符隔开的N2个整数,它们即为二维数组中的N2个元素,输入顺序从二维数组的第一行开始向下逐行输入,同一行数据从左向右逐个输入。

数组中的数字会保持在[-127,127]的范围内。

输出格式
输出一个整数,代表最大子矩形的总和。

数据范围
1≤N≤100
输入样例:
4
0 -2 -7 0 9 2 -6 2
-4 1 -4 1 -1

8 0 -2
输出样例:
15

这个题就是最长子序和的二维版本,一维用暴力,一维用DP就可以了hh,没什么好说的,来看代码。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<limits.h>

using namespace std;

const int N=110;

int g[N][N];
int n;

int main(){
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);

    cin>>n;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            cin>>g[i][j];
            g[i][j]+=g[i-1][j];
        }
    
    int res=INT_MIN;

    for(int i=1;i<=n;i++)
        for(int j=0;j<i;j++)
        {
            int last=0;
            for(int k=1;k<=n;k++)
            {
                last=max(last,0)+g[i][k]-g[j][k];
                res=max(res,last);
            }
        }

    cout<<res<<endl;
    return 0;
}

任务

今天某公司有M个任务需要完成。

每个任务都有相应的难度级别和完成任务所需时间。

第i个任务的难度级别为yi,完成任务所需时间为xi分钟。

如果公司完成此任务,他们将获得(500 * xi + 2 * yi)美元收入。

该公司有N台机器,每台机器都有最长工作时间和级别。

如果任务所需时间超过机器的最长工作时间,则机器无法完成此任务。

如果任务难度级别超过机器的级别,则机器无法完成次任务。

每台机器一天内只能完成一项任务。

每个任务只能由一台机器完成。

请为他们设计一个任务分配方案,使得该公司能够最大化他们今天可以完成的任务数量。

如果有多种解决方案,他们希望选取赚取利润最高的那种。

输入格式
输入包含几个测试用例。

对于每个测试用例,第一行包含两个整数N和M,分别代表机器数量和任务数量。

接下来N行,每行包含两个整数xi,yi,分别代表机器最长工作时间和机器级别。

再接下来M行,每行包含两个整数xi,yi,分别代表完成任务所需时间和任务难度级别。

输出格式
对于每个测试用例,输出两个整数,代表公司今天可以完成的最大任务数以及他们将获得的收入。

数据范围
1≤N,M≤100000,
0<xi<1440,
0≤yi≤100
输入样例:
1 2
100 3
100 2
100 1
输出样例:
1 50004

贪心策略:按第一个为第一关键字,第二个为第二关键字排序,真的没什么好说的,和防晒那题很像,基操hh,因为第二关键字根本无法改变局面,最多也只有100。~ 。~

#include<iostream>
#include<algorithm>
#include<cstring>
#include<set>

#define pii pair<int,int>
#define ll long long

using namespace std;

const int N=100010;

pii mach[N],task[N];
int n,m;

inline int calc(const pii &p)
{
    return 500*p.first+2*p.second; 
}

int main(){
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);

    while(cin>>n>>m)
    {
        for(int i=1;i<=n;i++)
            cin>>mach[i].first>>mach[i].second;
        for(int i=1;i<=m;i++)
            cin>>task[i].first>>task[i].second;
        sort(mach+1,mach+n+1);
        sort(task+1,task+m+1);
        multiset<int> s;
        ll res=0,cnt=0;
        for(int i=m,j=n;i>=1;i--)
        {
            while(j>=1&&task[i].first<=mach[j].first) s.insert(mach[j--].second);
            auto it=s.lower_bound(task[i].second);
            if(it!=s.end())
            {
                res+=calc(task[i]);
                s.erase(it);
                cnt++;
            }
        }
        cout<<cnt<<" "<<res<<endl;    
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值