复数乘法

复数可以写成 (A+Bi) 的常规形式,其中 A 是实部,B 是虚部,i 是虚数单位,满足 i​2=−1;也可以写成极坐标下的指数形式 (R×e​(Pi)),其中 R 是复数模,P 是辐角,i 是虚数单位,其等价于三角形式 R(cos§+isin§)。

现给定两个复数的 R 和 P,要求输出两数乘积的常规形式。

输入格式:
输入在一行中依次给出两个复数的 R1, P​1,R​2,P​2,数字间以空格分隔。

输出格式:
在一行中按照 A+Bi 的格式输出两数乘积的常规形式,实部和虚部均保留 2 位小数。注意:如果 B 是负数,则应该写成 A-|B|i 的形式。

输入样例:

2.3 3.5 5.2 0.4

输出样例:

-8.68-8.23i

解题思路:
Alice:看起来挺简单的。
Bob: 看通过率就知道这题有坑。
Alice: 哪有坑啊?
Bob: 没看出来,先试试吧。
Alice: 有坑,后两个测试点过不去。
Bob: 看下别人怎么做的?
Alice: 你就不能自己想出来吗?
Bob: 想出来,我不想出来。╭(╯^╰)╮
Alice: 我知道了,截断?浮点数的误差?-0.00?
Bob: (^U^)ノ~YO不错不错,应该是最后一个。保留两位小数其实是去掉了两位小数位后面的位,也就是截断。这样就可能出现问题,比如说-0.001截断之后变成了-0.00,这时候应该把符号去掉的。
Alice: 还有这样的题目啊》》
Bob:看起来不像是光明正大的考察,其实是难度增加了。明天要是晴天就好了~

顺便复习一下复数的运算法则

  • a+bi 和 c+di
  • 加法:(a+c) + (b+d)i
  • 减法:(a-c) + (b-d)i
  • 乘法:(ac-bd) + (bc+ad)i
  • 除法:(ac+bd)/(cc+dd) + (bc+ad)/(cc+dd)i

易错点:

  • 保留两位小数,意味着“截断”,截断就有可能出现 - 0.00的情况。如 "{:.2f}+{:.2f}i".format(-0.001, 1251314)"

大C的AC

#include <stdio.h>
int main(){
    double r1,p1,r2,p2;      
    double a, b;
    scanf("%lf %lf %lf %lf", &r1, &p1, &r2, &p2);
    a = r1 * r2 * cos(p1 + p2);    
    b = r1 * r2 * sin(p1 + p2);
    if(a < 0 && a > -0.005) a = 0;  
    if(b < 0 && b > -0.005) b = 0;
    printf("%.2lf%+.2lfi", a, b);
    return 0;
}

Java的AC

import java.util.Scanner;
 
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		double r1 = sc.nextDouble();
		double p1 = sc.nextDouble();
		double r2 = sc.nextDouble();
		double p2 = sc.nextDouble();
		double a = r1 * r2 * Math.cos(p1+p2);
		double b = r1 * r2 * Math.sin(p1+p2);
		if (a < 0 && a > -0.005) {
			a = 0;
		}
		if (b < 0 && b > -0.005) {
			b = 0;
		}
		System.out.printf("%.2f%+.2fi\n", a, b);//%+.2f是输出保留两位小数的浮点数,且必须输出符号
	}
}

python的AC

import math
# 需要使用math计算三角函数
def main():
    
    R1, P1, R2, P2 = (float(x) for x in input().split())
    # 接收输入的两个复试,其中R 和 P分别是复数模和幅角
    # 我们使用复数的指数形式来计算两个复数的乘法。即(R1 * exp​(P1)​​ ) * (R2 * exp​(P2)​​ ) == (R1 * R2 * exp​(P1 + P2)​​ )
    A, B = to_ab(R1 * R2, P1 + P2)
    # 然后我们把复数的指数形式转换成普通形式,其中A = R * cos(P) , B = R * sin(P)。即通过复数的三角形式完成转换。
    if abs(A) < 0.01:
        # 由于结果要求保留两位小数,两位小数后面的位将被截断。
        # 如 - 0.001将变成-0.00,这是不满足要求的,所以这里直接置零比较好。
        A = 0
    if abs(B) < 0.01:
        # 同上
        B = 0
        
    if B < 0:
        # 按照要求,保留两位小数,如果 B<0 输出A-|B|i
        answer = "{:.2f}-{:.2f}i".format(A, abs(B))
    else:
        answer = "{:.2f}+{:.2f}i".format(A, B)
    print(answer)


def to_ab(R, P):
    """通过复数的三角形式将复数从指数形式变成普通形式。输入是指数形式中的 复数模 和 幅角,输出为 复数的实部和虚部。"""	
    return R * math.cos(P), R * math.sin(P)

if __name__ == '__main__':
    main()

别人家的AC

import math
a = [float(i) for i in input().split()]
x1 = a[0]*math.cos(a[1])
x2 = a[0]*math.sin(a[1])
y1 = a[2]*math.cos(a[3])
y2 = a[2]*math.sin(a[3])
z1 = x1*y1-x2*y2
z2 = x1*y2+x2*y1
if z1+0.005>=0 and z1<0:
    z1 = '0.00'
else:
    z1 = '%.2f'%z1
if z2+0.005>=0 and z2<0:
    z2 = '+0.00i'
elif z2>=0:
    z2 = '+%.2fi'%z2
else:
    z2 = '%.2fi'%z2
print(z1+z2)

总结:

数列的片段和

给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段。例如,给定数列 { 0.1, 0.2, 0.3, 0.4 },我们有 (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4) (0.2) (0.2, 0.3) (0.2, 0.3, 0.4) (0.3) (0.3, 0.4) (0.4) 这 10 个片段。

给定正整数数列,求出全部片段包含的所有的数之和。如本例中 10 个片段总和是 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0。

输入格式:
输入第一行给出一个不超过 10^​5的正整数 N,表示数列中数的个数,第二行给出 N 个不超过 1.0 的正数,是数列中的数,其间以空格分隔。

输出格式:
在一行中输出该序列所有片段包含的数之和,精确到小数点后 2 位。

输入样例:

4
0.1 0.2 0.3 0.4

输出样例:

5.00

思路
这个题目很有意思,其实是一个找规律的题目,看上去很复杂,实际上如果动手写一写就可以展开发现规律。
就拿案例来举例子:

  • 对0.1来说,0.1需要加的次数如下:
  • 0.1,(0.1,0.2),(0.1,0.2,0.3),(0.1,0.2,0.3,0.4),一共4次。
  • 对于0.2来说,0.2需要相加的次数如下:
  • 0.2,(0.1,0.2),(0.2,0.3),(0.1,0.2,0.3),(0.2,0.3,0.4),(0.1,0.2,0.3,0.4),一共6次。
  • 发现了没有什么规律?

每个数出现的次数与它所在的位置是相关的!因为0.1左边没有数字,所以0.1只能放在开头,因此只有4种组合,同理,0.4右边没有数字,所以只能放在结尾,也是4种组合。

因此我们可以根据数字所在的位置列出通式:

出现次数为(i + 1) * (n - i)。
但((i + 1) * (n - i))在运算过程中会发生溢出。就做了更改:
先让arr 和 (i + 1)相乘,转化为double,再乘以(n - i)就可以避免溢出的问题了。

因此求和直接用一条语句即可:

sum = sum + ((i + 1) * arr * (n - i));

大C的AC

#include <stdio.h>
int main(){
	int n,i;
	scanf("%d",&n);
	double arr,sum;
	for(i=0;i<n;i++){
		scanf("%lf",&arr);
		sum=sum+(arr*(n-i)*(i+1)); 
	}
	printf("%.2lf",sum);
	return 0;
}

Java的伪AC

//有两个测试点超时了
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		@SuppressWarnings("resource")
		Scanner in = new Scanner(System.in);
		int n=in.nextInt();
		double sum=0,arr;
		for(int i=0;i<n;i++) {
			arr=in.nextDouble();
			sum=sum+(arr*(n-i)*(i+1));
		}
		System.out.printf("%.2f",sum);
	}
}

python的AC

n = int(input())
m = [float(i) for i in input().split()]
rst = 0
for i in range(n):
    rst += m[i] * (n - i) * (i + 1)
print('{:.2f}'.format(rst))

整数转罗马数字

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。

示例 1:

输入: 3
输出: "III"

示例 2:

输入: 4
输出: "IV"

示例 3:

输入: 9
输出: "IX"

示例 4:

输入: 58
输出: "LVIII"
解释: L = 50, V = 5, III = 3.

示例 5:

输入: 1994
输出: "MCMXCIV"
解释: M = 1000, CM = 900, XC = 90, IV = 4.

大C的初代

#include <stdio.h>
int main(){
	int arr[13]={1000,900,500,400,100,90,50,40,10,9,5,4,1}; 
    char *str[13]={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
    int i,num;
    scanf("%d",&num);
    for(i=0;i<13;i++){
    	while(arr[i]<=num){
    		num=num-arr[i];
    		printf("%s",str[i]);
		}
	}
	printf("\n");
	return 0;
}

大C的二代

char * intToRoman(int num){
    char * prm[] = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
    int doc[] = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
    char * sam = (char *)malloc(sizeof(char)* 20);//生成一个动态字符数组20个够了
    int n = num;
    sam[0] = '\0';
        for(int i = 0; i < 13; i++) {
            while (n >= doc[i]) {
                n-=doc[i];
                strcat(sam,prm[i]);//把对应的罗马数字加入字符串中
            }
        }
    return sam;
}

JAVA的

class Solution {
    public String intToRoman(int num) {
        int arr[]=new int[]{1000,900,500,400,100,90,50,40,10,9,5,4,1};
        String strs[]=new String[]{"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        String str="";
        //从最大的开始算。
        for (int i = 0; i < 13; i++) {// >=的意思就是使用多个arr[i],比如3999,要有3个1000。 
			 while(num>=arr[i]){ 
				 num = num - arr[i]; 
				 str = str + strs[i]; 
				}
			if (num == 0)   break;
		}
		return str;
	}
}

python的

class Solution:
    def intToRoman(self, num):
        number = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
        luoma = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I']
        shuru = ''
        for i in range(len(number)):
            while num >= number[i]:
                num = num - number[i]
                shuru = shuru + luoma[i]
        return shuru

罗马数字转整数

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  • I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  • X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  • C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。

示例 1:

输入: "III"
输出: 3

示例 2:

输入: "IV"
输出: 4

示例 3:

输入: "IX"
输出: 9

示例 4:

输入: "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.

示例 5:

输入: "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.

思路

  • 定义一个双字母在前,单字母在后的String型数组,定义与之对应数字的数组,遍历s,先判断是否是双字母所代表的数字,再判断单字母所代表数字,将对应数字相加即可;

JAVA的

class Solution {
    public int romanToInt(String s) {
        String[] roman = { "IV", "IX", "XL", "XC", "CD", "CM", "I", "V", "X", "L", "C", "D", "M" };
        int[] nums = { 4, 9, 40, 90, 400, 900, 1, 5, 10, 50, 100, 500, 1000 };
        int num = 0;
        while (s.length() > 0) {
            for (int i = 0; i < roman.length; i++) {
                if (s.startsWith(roman[i])) {
                    num += nums[i];
                    s = s.substring(roman[i].length());
                    break;
                }
            }
        }
        return num;
    }
}

Python的

class Solution:
    def romanToInt(self, s: str) -> int:
        d= {'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000}
        ans = 0
        for i in range(len(s)):
            if i < len(s) - 1 and d[s[i]] < d[s[i+1]]:
                ans -= d[s[i]]
            else:
                ans += d[s[i]]
        return ans