算法练习 - 4

容斥原理

给出一个数N,求1至N中,有多少个数不是2 3 5 7的倍数。 例如N = 10,只有1不是2 3 5 7的倍数。
Input :输入1个数N(1 <= N <= 10^18)。
Output :输出不是2 3 5 7的倍数的数共有多少。
Sample Input :10
Sample Output :1

容斥原理:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
可见该文章帮助理解 容斥请添加图片描述
1、对于两个集合的表达式:A∪B =|A∪B| = |A|+|B| - |A∩B |
2、三个集合:|A∪B∪C| = |A|+|B|+|C| - |A∩B| - |B∩C| - |C∩A| + |A∩B∩C|
3、四个集合:|A∪B∪C∪D| = |A|+|B|+|C|+|D| - |A∩B| - |A∩C| - |A∩D| - |B∩C| - |B∩D|- |C∩D| + |A∩B∩C|+ |A∩B∩D|+ |A∩C∩D|+ |B∩C∩D| - |A∩B∩C∩D|

#include <stdio.h>
int main(){
	long long n ;
	// 2 3 5 7
	scanf("%lld", &n);
	long long count2 = n / 2;
	long long count3 = n / 3;
	long long count5 = n / 5;
	long long count7 = n / 7;
	long long count_1 = count2 + count3 + count5 + count7;
	long long count23 = n / (2 * 3);
	long long count25 = n / (2 * 5);
	long long count27 = n / (2 * 7);
	long long count35 = n / (3 * 5);
	long long count37 = n / (3 * 7);
	long long count57 = n / (5 * 7);
	long long count_2 = count23 + count25 + count27 + count35 + count37 + count57;
	long long count235 = n / (2 * 3 * 5);
	long long count237 = n / (2 * 3 * 7);
	long long count257 = n / (2 * 5 * 7);
	long long count357 = n / (3 * 5 * 7);
	long long count_3 = count235 + count237 + count257 + count357;
	long long count2357 = n / (2 * 3 * 5 * 7);
	long long count_4 = count2357;
	long long count = count_1 - count_2 + count_3 -count_4;
	printf("%lld\n",n - count);
	return 0;
}

Arranging the sheep

输⼊ 组⻓度为 的字符串。其中 . 代表草地, 代表⽺群。每次可以移动⼀只⽺,不可以移出边界。问:最少移动多少步,使得所有的⽺都挨在⼀块。(即⽺与⽺之间没有草地)。*
Input : 第一行包含一个整数t(1≤t≤104)。接下来是测试用例。每个测试用例的第一行包含一个整数n(1≤n≤106)。每个测试用例的第二行包含一个长度为n的字符串,由字符’组成。’(空格)和’*’(羊)——关卡的描述。它保证所有测试用例的n之和不超过106
Output : 对于每个测试用例,输出完成关卡所需的最小移动数。
Sample Input:
请添加图片描述
Sample Output :
1
0
0
0
9

使移动次数最少,那就让所有的羊往最终的羊靠拢

1、可以先找出最终件羊的位置,然后从该处分别往左右两边计算到每只羊有多少个空格(空格便是每只羊移动的次数),计算的同时将每只羊的空格数相加,最终结果即所有羊移动的总次数(python)

t = int(input().split()[0])
for i in range(t):
    n = int(input().split()[0])
    li = input()
    low = 0
    high = n - 1
    flag = 0
    mid = 0
    while low <= high :
        while low <= high :
            if li[low] == '.' :
                low += 1
            else :
                flag = 1
                mid = low
                low += 1
                break
        while (li[high] == '.') & (low <= high):
            high -= 1
        high -= 1
    if flag == 0:
        print(0)
        continue
    count = 0
    low = mid - 1;
    count_tmp = 0
    while low >= 0:
        if li[low] == '.' :
            count_tmp += 1
        else :
            count += count_tmp
        low -= 1
    high = mid + 1
    count_tmp = 0
    while high < n:
        if li[high] == '.':
            count_tmp += 1
        else:
            count += count_tmp
        high += 1
    print(count)

2、使用数组记录每只羊的位置,然后再计算(C++)

请添加图片描述

Ordinary Numbers

如果⼀个数字所有位数都是⼀样的,我们就称它为ordinary number。例如:1 5 99 是,而 100 2021 不是。给定一个数字n,找到1-n之间有多少个这样的数字。
Input : 第一行包含一个整数t(1≤t≤104)。接下来是测试用例。每个测试用例的特征是一个整数n(1≤n≤109)。
Output : 对于每个测试用例,输出从1到n的数字中ordinary number的数量。
Sample Input :
6
1
2
3
4
5
100
Sample Output :
1
2
3
4
5
18

个级别的数字最多有9个,十级别的也有9个,百级别的数字也是9个……也就是说,每一个级别的数字都是有9个ordinarynumber。举一个例子,加入这个数是3234,这个数字有四个级别,个十百级别的都正好各有9个,我们来分析千级别的,3000-4000间ordinary number为3333,而3333比3234大,所以千级别的数字有3-1=2个ordinary number,如果把则个数换成3434,则千级别的ordinary number正好3个。

t = int(input().split()[0])
for i in range(t) :
    n = int(input().split()[0])
    li = list(str(n))
    length = len(li)
    if length == 1:
        print(n)
        continue
    li_tmp = [li[0]] * length
    num1 = int("".join(li))
    num2 = int("".join(li_tmp))
    count_tmp = 0
    if num1 < num2 :
        count_tmp = int(li[0]) - 1
    else :
        count_tmp = int(li[0])
    count = count_tmp + (length - 1) * 9 
    print(count)

Stone Game

给定一个数组,其中的每个数代表这个石头的大小,现在要求砸碎最大和最小的石头,每次只能从最左边或者最右边开始砸且每次只能砸一个石头,问一共最少需要砸碎多少石头才能把最大和最小的石头都砸碎。
Input : 第一行包含一个整数t(1≤t≤100)。接下来是测试用例。每个测试用例的第一行包含一个整数n(2≤n≤100)——石头的数量。第二行包含n个不同的整数a1,a2,…,an(1≤ai≤n,ai代表石头的大小)。
Output : 对于每个测试用例,输出摧毁具有最大和最小的石头所需的最小次数。
Sample Input :
5
5
1 5 4 3 2
8
2 1 3 4 5 6 8 7
8
4 2 3 1 8 6 7 5
4
3 4 2 1
4
2 3 1 4
Sample Output :
2
4
5
3
2

思路并不复杂,就是代码写的有些绕,因为经常需要判断哪个数更小,使用min函数或者写一个swap可能会更好
首先找出最小和最大的石头的位置,计算一下这两块石头:
(1)要砸到这块石头需要的最小次数
(2)是从左边开始砸还是从右边开始砸的
然后开始砸石头:
(1)若两块石头开始砸的方向是相同的,次数最大的那个就是最终结果
(2)若两块石头开始砸的方向不同:判断先砸较小次数a的那块石头,然后判断一下较大次数b的石头是原本的次数更小还是从a开始砸的次数更小,然后计算砸的总次数即可

t = int(input().split()[0])
for i in range(t) :
    n = int(input().split()[0])
    li = list(int(x) for x in input().split())
    count = 0
    length = len(li)
    mi = 0
    mx = 0
    for j in range(1, length) :
        if li[j] < li[mi] :
            mi = j
        if li[j] > li[mx] :
            mx = j
    if mi + 1 < length - mi:
        mi_count = mi + 1
        mi_d = 0
    else :
        mi_count = length - mi 
        mi_d = 1
    if mx + 1 < length - mx:
        mx_count = mx + 1
        mx_d = 0
    else :
        mx_count = length - mx
        mx_d = 1
    if mi_d != mx_d:
        if mi_count <= mx_count :
            if mx_count <= abs(mx - mi):
                count = mi_count + mx_count
            else:
                count = length - mx_count + 1
        else:
            if mi_count <= abs(mx - mi):
                count = mi_count + mx_count
            else:
                count = length - mi_count + 1
    else :
        if mi_count <= mx_count:
            count = mx_count
        else:
            count = mi_count
    print(count)

下面是另一个同学的代码,更简洁一些
请添加图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
算法图解-python.pdf》是一本介绍算法和使用Python语言实现算法的书籍。该书的目的是帮助读者了解算法的基本概念和原理,并通过Python编程实践来加深理解。 这本书以图解的方式呈现算法的思想和应用,使复杂的算法问题变得直观易懂。读者可以通过阅读该书,学习到各种常见的算法设计和解决思路,如排序算法、搜索算法、图算法等。同时,该书也会介绍一些高级算法,如动态规划、贪婪算法等,以及如何通过Python语言实现这些算法。 《算法图解-python.pdf》的内容结构清晰,通俗易懂。每个算法都有详细的解释和示例代码,读者可以通过实际编程来加深对算法的理解。此外,书中还包含了一些挑战性的练习题,供读者进一步巩固所学的知识。 通过阅读《算法图解-python.pdf》,读者不仅可以学习到算法的基本知识,还可以了解到如何运用Python语言实现这些算法。这对于刚开始学习算法和Python编程的读者来说是非常有帮助的。无论是计算机科学专业的学生,还是对算法感兴趣的爱好者,都可以从这本书中受益匪浅。 总之,《算法图解-python.pdf》是一本很好的算法入门书籍,以图解和Python编程为特色,适合各类读者学习和参考。通过阅读和实践,读者可以提高算法设计和编程实现的能力,为解决实际问题提供有效的思路和方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值