牛客练习赛15

A:

当吉姆刷到 牛客练习赛12 B.迷宫这题时,为了纪录二维迷宫中,每一步可以走的四个方向的位移量,写出的代码包含了以下段落:
int offset[4][2] = { (1, 0), (0, 1), (-1, 0), (0, -1) };
眼尖的读者们应该很快就发现这段程序码哪里出错了吧XD正确的写法应如下:
int offset[4][2] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
吉姆误把大括号打成了小括号于是实际上的四个位移量被记录成:(0,1),(0,-1),(0,0),(0,0)
经过这次经验,吉姆才知道原来逗号(comma)也是C / C ++的一种运算符(operator)。
吉姆开始好奇,给你一个只含数字,小括号,逗号的合法运算式,能否快速得到此算式的结果呢?请帮吉姆写一个计算这类的算式的程序吧〜
Note:
不熟悉逗号运算符的人可以参考 cppreference.com 里的說明
以下也给出简易的逗号运算符的定义:(若不小心与C++的规章有所出入,请以下列四条为准):
1.对于所有满足-2 31≤ x ≤2 31-1的整数x本身都是个合法的运算式,且此运算式的值就是该数字。(若x不是0,数字部分就不能以0开头,若是0,一定恰只有一个0.)
2.若E 1,E 2,...,E n都是合法的运算式,则E 1,E 2,...,E n也是个合法的运算式,并且其值为E n的值。
3.若E是个合法的运算式,则(E)也是个合法的运算式,其值为E的值。
无法用上列1,2,3项的关系推出的运算式,都是不合法的。
举例来说514,1,2,(-2147483648,2,4),(((0))),(1),(2)都是此题中合法的运算式,但0514,-02,(),(23,43))都是不合法的。

输入描述:

输入仅有一行,包含一个字串e,是一个仅由左右小括号'(',')',逗号',',以及整数所组成的合法运算式。

输出描述:

输出一行包含一个整数,代表输入所提供的运算式的运算结果
示例1

输入

(5,-14)

输出

-14

备注:

1≤|e|≤100
e中所有整数的范围为-231≤ x ≤231-1
e满足Note里提到的合法运算式
特别强调,e不包含' '(空格)

题目分析:简单分析可以知道,答案就是最后一个出现的数字

#include<bits/stdc++.h>
using namespace std;

int main()
{
    string str;
    cin>>str;
    int sum=0,flag=0;
    for (int i=0;i<str.size();i++) {
        if (str[i]=='('||str[i]==',') {
            flag=sum=0;
        }
        else if (str[i]>='0'&&str[i]<='9'||str[i]=='-'){
            if (str[i]=='-') flag=1;
            else sum=sum*10+str[i]-'0';
        }
    }
    cout<<(flag?(sum*-1):sum)<<endl;
    return 0;
}

B:

第一次期中考终于结束啦!沃老师是个语文老师,他在评学生的作文成绩时,给每位学生的分数都是一个小于10的非负小数。

Amy 8.999999999999999999999999999999999999999990000

Bob 8.9999999999999999999999999999999999999999800

Cat 8.9999999999999999999999999999999999999999899999999

沃老师并不会告诉大家分数的排名,但学生间竞争激烈,大家都想知道自己的作文成绩在班上的排名。
但由于作文分数的小数部分可能超级长,难以用肉眼比较两个数的大小关系,请你帮忙写个程序,把所有学生按照作文分数排序吧〜

输入描述:

输入共有N + 1行。
第一行有一个正整数N,代表班上有几个人。
接下来N行中的第i行,包含一个字符串namei,以及一个小数scorei,分别代表第i个人的名字以及第i个人的作文得分。

输出描述:

输出总共N行,每行由一个名字和一个小数构成,第i行代表着分数第i高的人的名字以及他的作文得分,代表作文得分的小数必须和输入一模一样,也就是原本末尾有多少零,输出也要有相同数量的零。
若分数相同,则名字字典序比较小的放在前面。
示例1

输入

3
Amy 8.999999999999999999999999999999999999999990000
Bob 8.9999999999999999999999999999999999999999800
Cat 8.9999999999999999999999999999999999999999899999999

输出

Amy 8.999999999999999999999999999999999999999990000
Cat 8.9999999999999999999999999999999999999999899999999
Bob 8.9999999999999999999999999999999999999999800

备注:

2≤N≤2×105
1≤字串名称的长度≤11
namei由数字及大小写英文字母组成
若i≠j,则namei≠namej
所有名称的长度总和≤6×105
scorei包含三个部分:整数部分,小数点,小数部分
  整数部分一定恰只有一个字元(数字'0'〜'9'之一)
  一定有小数点('.')
  小数部分由'0'〜'9'组成,长度可为0,也可以由字元'0'结尾
若把scorei视为字符串,所有scorei的长度总和≤6×105

题目分析:我们把成绩的末尾0去掉后保存到另一个string里面,然后可以直接根据字符串比较大小。

感觉这里面有一个坑,cmp函数如果你的参数不加引用就T了。

感觉合理的解释是:因为cmp函数被多次调用,不加引用,那么每一次都需要开一个空间,把实参传给形参,赋值过程很耗时。加了引用,就不需要重新赋值过程。

如有错,欢迎评论区给出正确解释,谢谢。

#include<bits/stdc++.h>
using namespace std;

const int maxn=2*1e5+100;
struct note{
    string name,score,pre;
}person[maxn];


void solve(string &s)
{
    int first=0;
    int len=s.size();
    for (int i=len-1;i>=0;i--) {
        if (s[i]=='0') first++;
        else break;
    }
    if (first<len) s=s.substr(0,len-first);
}
bool cmp(note &a,note &b)
{
    if (a.score==b.score) {
        return a.name<b.name;
    }
    return a.score>b.score;
}
int main()
{
    int n;
    cin>>n;
    for (int i=1;i<=n;i++) {
        cin>>person[i].name>>person[i].score;
        person[i].pre=person[i].score;
        solve(person[i].score);
    }
    sort(person+1,person+1+n,cmp);
    for (int i=1;i<=n;i++) {
        cout<<person[i].name<<" "<<person[i].pre<<endl;
    }
    return 0;
}

C

吉姆是个热爱算法竞赛的小朋友,平常的休闲活动就是刷 牛客网 的题目。

当吉姆刷到 wannafly挑战赛12 F.小H和圣诞树  这题时,颇为震惊,因为这是他第一次在wannafly挑战赛上看到作者提供的解答的时间复杂度的式子里含有根号的题目,于是吉姆就开始在网络上搜寻拥有类似时间复杂度解法的问题,并且看到了以下这题:

给你一个有 N 个点 M 条边的无向简单图,请算算此图中有几个三角形。我们称无序的三个点 x,y,z 为三角形,若且唯若 (x,y)、(y,z)、(x,z) 都是此图上的边。
吉姆 想了这个问题七天七夜后,他发现了一件事情:
(1) 对于任一个度数为 d 的点,我们可以用 O(d 2) 的时间复杂度来计算有多少三角形包含这该点。
吉姆 又想了这个问题七天七夜后,他又发现了一件事情:
(2) 对于任一个点,我们可以用 O(M) 的时间复杂度来计算有多少三角形包含该点。
吉姆又再想了这个问题十四天十四夜后,他忽然想到:
(3) 不如就把 (1) 和 (2) 的算法结合在一起!找一个恰当的整数s 若一个点度数小于等于s,就使用(1),否则就使用(2),经过缜密的时间复杂度分析,发现这么做的时间复杂度会是 ,取 ,时间复杂度就会是 。最后再把包含各个点的三角形数全部加起来再除以 3 就是答案了! (因为每个三角形会被算到三次。) (此时间复杂度的详细证明会在今天的题解中解说唷~)
但这个 s 的值究竟要设为多少呢?这就和 (1) 与 (2) 两种方法的执行时间的常系数有关了。
于是,吉姆为了透彻了解这个问题,就假定(1) 和(2) 的常系数分别是a 与b,这意思是:对于一个度数为d 的点,若使用(1),程式的执行时间和a×d 2 成正比;若使用(2),程式的执行时间则和b×M 成正比。
对于一个给定的图,吉姆想要知道对于不同的 a,b,s 的值要取多少比较好,并且求出 s 为该值时程式所需的执行时间!
在这个问题里,我们不会真的给你一个图,只会告诉你边数 M。并对于所有正整数 d,告诉你度数为 d 的点有几个。甚至,题目里给你的图不一定实际上存在的简单图(意即输入可能不是一个合法的简单图的度序列)。
大家好,以上是题目背景。(哈哈哈哈哈嚯嚯嚯嚯~)
给你两个正整数 M, L, 以及两个长度为 L 个正整数序列 deg 1,deg 2,..., deg L 和 freq 1, freq 2,..., freq L
(deg i 和 freq i 对应到 Background 里提到的问题的意思就是:度数为 deg i 的点 有 freq i 个。)
你要回答 Q 个问题,第 i 个问题会给你 2 个正整数 a i, b i,请找到一个整数 s 使得以下式子(E i) 的值最小:
(此式就是 Background 里提到的程式执行时间的估计函数)

输入描述:

 
 

输入共有 1+L+1+Q 行。 第一行有有两个正整数 M,L。 接下来的 L 行中的第 i 行有两个正整数 degi 和 freqi。 下一行有一个正整数 Q。 最后 Q 行中的第 i 行有两个正整数 ai, bi

输出描述:

对于每个询问都输出一行包含一个整数,代表式子 Ei 的最小值。
题目分析:题目很长,很烦。简单就是确定最优的s使得E最小。
一般情况下E和s的函数在区间内应该是凹函数,还有俩种特殊情况,单调增,单调减。

三分来求最优解,结果还需要对俩个极端情况(全是a,全是b)进行比较就好了。

因为是多组查询,我们需要进行一下预处理。

题目说的数据不超过long long,那是表示结果不超过,计算过程中就超过了。

还有更简单的做法!!!

import java.math.BigInteger;
import java.util.Scanner;

public class Main{
	final static int maxn=(int) (2*1e5+100);
	static BigInteger deg []= new BigInteger[maxn];
	static BigInteger freg []= new BigInteger[maxn];
	static BigInteger sum_a []= new BigInteger[maxn];
	static BigInteger sum_b []= new BigInteger[maxn];
	static int a,b;
    public static  BigInteger f (int pos) {
		BigInteger A=sum_a[pos].multiply(BigInteger.valueOf(a));
		BigInteger B=sum_b[pos+1].multiply(BigInteger.valueOf(b));
		return  A.add(B);
	}
    public static BigInteger min(BigInteger a,BigInteger b) {
    	if (a.compareTo(b)>0) return b;
    	else return a;
    }
    
    public static void main(String[] args) {
    	Scanner cin=new Scanner(System.in);
    	BigInteger M=cin.nextBigInteger();
    	int L=cin.nextInt();
    	for (int i=1;i<=L;i++) {
    		deg[i]=cin.nextBigInteger();
    		freg[i]=cin.nextBigInteger();
    	}
    	sum_a[0]=sum_b[L+1]=BigInteger.valueOf(0);
    	for (int i=1;i<=L;i++) {
    		sum_a[i]=sum_a[i-1].add(deg[i].multiply(deg[i].multiply(freg[i])));
    	}
    	for (int i=L;i>=1;i--) {
    		sum_b[i]=sum_b[i+1].add(freg[i].multiply(M));
    	}
    	int Q=cin.nextInt();
    	while ((Q--)>0) {
    		a=cin.nextInt();
    		b=cin.nextInt();
    	    int left=0,right=L;
    		while (right-left>1) {
    			int mid=(right+left)/2;
    			int mmid=(mid+right)/2;
    			if (f(mid).compareTo(f(mmid))>0) left=mid;
    			else right=mmid;
    		}
    		BigInteger ans=min(f(left),f(right));
    		BigInteger res=min(sum_a[L].multiply(BigInteger.valueOf(a)),sum_b[1].multiply(BigInteger.valueOf(b)));
    		ans=min(ans,res);
    		System.out.println(ans);
    	}
     	cin.close();
    }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值