第一次双周赛题解

1. Lily

百合花(Lily)是一种美丽的花。她通常一年只开一次花,所以如果你看到百合花盛开,它会非常珍贵。然而,她对猫有剧毒,所以你必须注意让好奇的猫远离可爱的百合花。

你有n个网格的土壤土地排成一行,从1到n,其中一些是百合花。我们不想伤害百合,也不想伤害猫。你可以在网格上放一些猫粮,但对于任何有猫粮的网格i,在区域[i−1,i+1]不得含有百合花。你喜欢猫和百合,所以你想最大限度地增加有猫粮的格子。

设计满足上述要求的计划。

输入格式:

有一个整数n(1≤n≤1000)表示网格的数量。

第二行包含仅由“L”和“.”组成的字符串R,表示有和没有百合花的格子。

输出格式:

输出包含一行,字符串R′仅由“L”、“”组成和“C”,其中“C”表示在满足上述要求的同时分配给R中空网格的猫粮。

输入样例:

在这里给出一组输入。例如:

5
..L..

输出样例:

在这里给出相应的输出。例如:

C.L.C

一道非常简单的模拟题,我们只需要一个用于标记的数组。在这里我用的是book数组,我们只需要将放百合花的位置以及百合花左右的位置标记为1,然后在book[i]=0的位置放猫粮,(即将.改为C),然后输出即可.

完整代码如下:

#include<iostream>
using namespace std;
int main(){
    int n;
    int book[1005]={0};  //用于标记的数组
    char a[1005]={0};
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];  //输入字符串
    }
    for(int i=1;i<=n;i++){
        if(a[i]=='L'){
            book[i]=1;
            book[i+1]=1;
            book[i-1]=1;   //如果是百合花,则将改格子和左右两格标记为1
        }
    }
    for(int i=1;i<=n;i++){
        if(book[i]!=1){
            a[i]='C';  //在不为1的位置放猫粮
        }
    }
    for(int i=1;i<=n;i++){
        cout<<a[i];  //输出
    }
    system("pause");
    return 0;
}

2. a * b

给出两个不超过1000位的十六进制数a,b。求ab的值

输入格式:

输入共两行,两个十六进制的数

输出格式:

输出一行,表示ab

输入样例:

在这里给出一组输入。例如:

1BF52
1D4B42

输出样例:

在这里给出相应的输出。例如:

332FCA5924

这是一道典型的高精度的题目,但是不同的是这里的数字是16进制的数,所以在存储每个位置的数字时,我们要注意字母与数字的转化.同样,在输出时也要注意输出数字若大于等于10,就要转化成字母.其他的与普通的高精度一样.

完整代码如下:

#include<iostream>
using namespace std;
string a,b;
int numarr1[1005],numarr2[1005];
long res[2000];
int len1,len2,len3;
char str[6]={'A','B','C','D','E','F'};  //便于在输出时输出字母
void turn(){
    int size1=0,size2=0;
    len1=a.length();
    len2=b.length();
    for(int i=len1-1;i>=0;i--){  //倒叙存放,便于计算
        if(a[i]>='0'&&a[i]<='9'){
            numarr1[size1]=a[i]-'0';  //如果是数字时就存放
            size1++;
        }
        else if(a[i]>='A'&&a[i]<='Z'){
            numarr1[size1]=a[i]-'A'+10;  //如果是字母,只需减去字母A,再加上10即可
            size1++;
        }
    }        
    for(int i=len2-1;i>=0;i--){
            if(b[i]>='0'&&b[i]<='9'){
                numarr2[size2]=b[i]-'0';
                size2++;
            }
            else if(b[i]>='A'&&b[i]<='Z'){
                numarr2[size2]=b[i]-'A'+10;  //与上相同
                size2++;
            }
        }
}
void mul(){  //相乘的函数
    int start=0;
    for(int i=0;i<len1;i++){
        start=i;
        for(int j=0;j<len2;j++){
            res[start]+=numarr1[i]*numarr2[j];  //进行相乘的函数
            start++;
        }
        if(i==len1-1){
            len3=start;  //
        }
    }
}
void change(){
    int i=0;
    while(i<len3){
        res[i+1]+=res[i]/16;
        res[i]%=16;
        i++;
        if(res[len3]>0){
            len3++;
        }        
    }

}
int main(){
    cin>>a>>b;
    turn();
    mul();
    change();
    for(int i=len3-1;i>=0;i--){
        if(res[i]>=10){
            cout<<str[res[i]-10];
            continue;
        }
        cout<<res[i];
    }
    system("pause");
    return 0;
}

3. 山头狙击战

题目描述

小明为了掩护大部队,单枪匹马同敌人周旋,后来被敌人包围在某山头……等等,为什么怎么听怎么像狼牙山五壮士!不过不用着急,这次小明携带了足够的弹药,完全可以将涌上来的敌人一个一个干掉。小明是个神枪手,只要他的枪膛中有子弹,他就能将在他射程m(用从敌人位置到山头的直线距离算)以内的一个敌人瞬间射杀。但如果在射程内没有敌人,出于节约子弹考虑和面子问题,小明会等待敌人靠近然后射击。
正当小明为自己的强大而自我膨胀时,他忽然发现了一个致命的失误:他携带的枪是单发枪,每射出一发子弹都必须花k秒钟的时间装子弹。而凶残的敌人才不会花时间等你换子弹呢。他们始终在以1m/s的速度接近山头。而如果在一个敌人到达山头时小明无法将他击毙,那么我们可怜的小明就将牺牲在敌人的刺刀下。现在小明用心灵感应向你发出求助:要保住自己的性命并且歼灭所有敌人,小明最多只能用多少时间给枪装上一发子弹?
说明:假设一开始小明的枪中就有一发子弹,并且一旦确定一个装弹时间,小明始终会用这个时间完成子弹的装卸。希望你能帮助小明脱离险境。

输入格式

每组输入数据,第一行有两个整数n和m,(2≤n≤100,000; 1≤m≤10,000,000)n代表敌人个数,m代表小明的射程。
接下来有n行,每行一个整数mi,(1≤mi≤10,000,000),代表每个敌人一开始相对山头的距离(单位为米)。

输出格式

每组输出数据仅有一个整数,代表小明的换弹时间(单位为秒)。

样例输入

6 100
236
120
120
120
120
120

样例输出

25

显然,这是一道关于二分答案的题目.但是这里有几个需要注意的事:

1.要等到敌人到射程才能开始开枪.所以敌人的初始位置需要进行更新.

2.因为这个数据规模有点大(10000000),所以,我们在模拟敌人前进不可能对全部都进行模拟前进(如果这样就必定TLM了),需要一个一个的来进行模拟.

所以,在注意好这些问题的情况下,我们只需对开枪和敌人前进的过程进行模拟即可了.

完整注释代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,m;    
int enemy[100005]={0};   //用于表示敌人与小明的距离
int a,flag=0;  
bool judge(int mid){
    int fir=0;
    int num=1;
    int j;
    int book[100005]={0};    //用于标记敌人是否死亡
    int temp[100005];  //复制敌人的位置
    for(int i=0;i<n;i++){
        temp[i]=enemy[i];
    }
    if(temp[0]>=m){
        a=temp[0]-m;  
        for(int i=0;i<n;i++){
            temp[i]-=a;  //更新起始位置
        }        
    }   
    while(book[n-1]!=1){
        if(temp[fir]<=m){  //如果在射程里就标记为1,表示死亡
            book[fir]=1;
            if(fir==n-1){
                return true;  //如果最后一个敌人倒下了,则小明胜利了,则返回true
            }
            fir++;  //表示下一个敌人
        }
        if(temp[fir]-num*mid<=m){
            j=num;
            num++;  //到了射程以内,则只需移动一次
        }
        else{
            while(temp[fir]-num*mid>m){  //如果没有到射程,则一直向前移动
                num++;
                j=num;
            }            
        }
            temp[fir]-=j*mid;  //向前移动的距离
            if(temp[fir]<0&&book[fir]==0){  //如果小于0,表示已经到达山头,则小明要死在敌人残忍的刺刀下了,则返回false
                return false;
            }               
    }
    return true;
}
int main(){
    bool ret;
    int l=0;
    int mid;
    int r=100000;
    mid=(l+r)/2; 
    cin>>n>>m;
    for(int i=0;i<n;i++){
        cin>>enemy[i];
    }
    sort(enemy,enemy+n);  //要先进行排序,这样才能一个一个模拟前进 
    int ret1;  
    while(l!=r-1){//二分答案
        ret=judge(mid);
        if(ret){
            ret1=mid;
            l=mid;
        }
        else{
            r=mid;
        }        
        mid=(l+r)/2;
    }
    cout<<ret1;
    system("pause");
    return 0;
}

4. Reversing Linked List

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K=3, then you must output 3→2→1→6→5→4; if K=4, you must output 4→3→2→1→5→6.

Input Specification:

Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤105) which is the total number of nodes, and a positive K (≤N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.

Then N lines follow, each describes a node in the format:

Address Data Next

where Address is the position of the node, Data is an integer, and Next is the position of the next node.

Output Specification:

For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.

Sample Input:

00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

Sample Output:

00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

这是逆转链表的一道题,链表我倒是会,~~但是我不会逆转链表该怎么办呢?~~所以,我就想到了c++标准库里的reverse函数.对于reverse函数的用法是:reverse(arr,arr+i)arr也就是数组中的元素的地址,arr+i也就是需要逆转的数据终点.所以,我们需要将链表的地址存放到数组里头,然后利用reverse函数进行逆转.

完整代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int head,n,k;     
    cin>>head>>n>>k;   
    int address1[100000],data1[100000],next1[100000];  //存放地址,数据,和后继
    for(int i=0;i<n;i++){    
        int add;
        cin>>add;
        cin>>data1[add]>>next1[add]; //输入
    }
    int num=0;
    while(head!=-1){
        address1[num++]=head;  //存放地址
        head=next1[head];  //更新地址
    }
        for(int i=0;i<num-num%k;i+=k){
            reverse(address1+i,address1+i+k);  //以k为单位进行逆转     
        }        
    for(int i=0;i<num-1;++i){
        printf("%05d %d %05d\n",address1[i],data1[address1[i]],address1[i+1]);  //输出时要进行补0          
    }
    printf("%05d %d -1",address1[num-1],data1[address1[num-1]]);  //输出时要补0
    return 0;
}

5. 一元三次方程

已知该方程有三个不同的实数根(根与根之差的绝对值≥10−6),且根范围均在[p,q]之间,你需要解出这个方程的三个根。

输入格式:

第一行一个整数T(1≤T≤1000),表示有T组数据

接下来T行,每行6个实数,分别表示a,b,c,d,p,q

数据保证:−102≤p,q≤102,且对于∀x∈[p,q],−106≤f(x)≤106

输出格式:

输出三个实数,表示方程的三个解。

你的答案可以以任意顺序输出。

一个答案被认为是正确的,当且仅当其与标准答案的绝对误差不超过10−6

输入样例:

在这里给出一组输入。例如:

1
1.000000 -5.000000 -4.000000 20.000000 -10.000000 10.000000

输出样例:

在这里给出相应的输出。例如:

-2.000000 2.000000 5.000000

提示1:

样例所给方程的图像如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ki0naMc-1668603941026)(C:\Users\zc\Desktop\补题题解\img\0600ddcf-0496-4697-a16c-5f7ceccf042f.png)]

这道题需要用到二分搜索,但是要先确定搜索的范围.因为这个方程必定有3个解,说明必定在p和q的区间里有极大值点a和极小值点b,则方程的解也就是在(p,min{a,b})(min{a,b},max{a,b})(max{a,b},q)这三个区间内,所以我们只需先确定a和b就可以进行二分搜索.显然,a和b的点导数为0,所以我们只需用到初中就学到的求根公式就可以解出这两个点的坐标.

完整代码如下:

#include<iostream>
#include<cmath>
#include<iomanip>
using namespace std;   
double f(double x,double a,double b,double c,double d){  //求函数值
    double f;
    f=a*pow(x,3.0)+b*pow(x,2.0)+c*x+d;
    return f;
}
double findx(double l,double r,double a,double b,double c,double d){  //二分搜索
    double mid;
    while(abs(l-r)>pow(10.0,-7.0)){  //控制精度
        mid=(l+r)/2.0;
        if(f(mid,a,b,c,d)*f(l,a,b,c,d)>0){
            l=mid;
        }
        else{
            r=mid;
        }
    }
    return mid;
}
void findm(double a,double b,double c,double d,double p,double q){
    double x1,x2;
    double ret1,ret2,ret3;
    x1=((-2)*b+pow(4*b*b-12*a*c,0.5))/(6*a);
    x2=((-2)*b-pow(4*b*b-12*a*c,0.5))/(6*a);   //求极值点的横坐标
    if(x1>x2){
        ret3=findx(x1,q,a,b,c,d);
        ret1=findx(p,x2,a,b,c,d);
        ret2=findx(x2,x1,a,b,c,d);        //在x1>x2状态下进行二分搜索
    }       
    else{
        ret3=findx(x2,q,a,b,c,d);
        ret1=findx(p,x1,a,b,c,d);
        ret2=findx(x1,x2,a,b,c,d);  	//在x2>x1状态下进行二分搜索
    }
    cout<<ret1<<" "<<ret2<<" "<<ret3<<endl;  //输出结果
}
int main(){
    double arr[1005][6];  //用于存放每组输入的数据
    cout<<fixed<<setprecision(9);  
    int n;
    cin>>n;
    for(int i=0;i<n;i++){
        for(int j=0;j<6;j++){
            cin>>arr[i][j];  
        }
    }
    for(int i=0;i<n;i++){
        findm(arr[i][0],arr[i][1],arr[i][2],arr[i][3],arr[i][4],arr[i][5]);  //进行计算
    }
    system("pause");
    return 0;
}

完美结束!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值