基础算法题(1) - 数字、模拟

  • T1

一个数的十进制表示若只有1,0则称这个数是quasibinary,给定一个正整数n(1 ≤ n ≤ 10e6),把它表示成最少个数quasibinary的和。
input
9
output
9
1 1 1 1 1 1 1 1 1
input
32
output
3
10 11 11

解:
对一个n,如5203,每一位若不是0,给一个1,否则给0,
5203 - 1101 = 4102
4102 - 1101 = 3001
3001 - 1001 = 2000
2000 - 1000 = 1000
2000 - 1000 = 0
则 5203 = 1101 + 1101 + 1001 + 1000 + 1000

code(go):

package main

import (
    "fmt"
    "strconv"
)

func main() {
    var n int
    fmt.Scan(&n)

    k := 0
    ans := ""
    for n != 0 {
        cur := n
        m := 0
        p := 1
        for cur != 0 {
            if cur%10 != 0 {
                m += p
            }
            p *= 10
            cur /= 10
        }

        k++
        n -= m
        ans += strconv.Itoa(m)
        ans += " "
    }

    fmt.Println(k)
    fmt.Println(ans)
}
  • T2(617B)

0, 1组成的序列,拆分称若干组,没组和为1,有多少拆分法?
Examples
input
3
0 1 0
output
1
input
5
1 0 1 0 1
output
4
相邻两个1之间有多少个数,这一段就有多少种不同的组合。
代码(python3)

import sys

n = int(input())
an = list(map(int, sys.stdin.readline().split()))

ans = 0
pre = 0
for i in range(n):
    if an[i] is 1:
        if ans is 0:
            ans = 1
        else:
            ans *= (i - pre)
        pre = i

print(ans)
  • T3(574A)

序列an,每次操作可使任一个数减1,an[0]加1,最少多少次操作可使an[0]变为最大数?
Examples
input
5
5 1 11 2 8
output
4
input
4
1 8 8 8
output
6
input
2
7 6
output
0

每次操作找到序列中最大值减1,an[0]加1即可。
代码(python3):

import sys

n = int(input())
an = list(map(int, sys.stdin.readline().split()))

ans = 0
while True:
    max_i = 0
    for i in range(1, n):
        if an[i] >= an[max_i]:
            max_i = i

    if max_i is 0:
        break
    else:
        an[0] += 1
        an[max_i] -= 1
        ans += 1

print(ans)
  • T4(115A)

Examples
input
5
-1
1
2
1
-1
output
3

第一行为人数n,后面n行表示第i个人的直接领导,-1表示没有直接领导。
现在要组织一个活动,要求分成若干组,每个组中不能存在领导关系,求最小组数。

解:
例子给出的领导关系为:
1->2->3
4->1
5
则最少组数为最长的领导链长度3

package main

import (
    "fmt"
)

func main() {
    var n int
    fmt.Scan(&n)

    pn := make([]int, n+1, n+1)
    for i := 0; i < n; i++ {
        fmt.Scan(&pn[i])
    }

    ans := 0
    for i := 0; i < n; i++ {
        depth := 1
        cur := pn[i]
        for cur != -1 {
            cur = pn[cur-1]
            depth++
        }

        if ans < depth {
            ans = depth
        }
    }

    fmt.Println(ans)
}
  • T5(567B)

Examples
input
6
+ 12001
- 12001
- 1
- 1200
+ 1
+ 7
output
3
input
2
- 1
- 2
output
2
input
2
+ 1
- 1
output
1

第一行为记录数n,后面n行表示n条记录,
+ x 表示编号为x的人进入
- x 表示编号为x的人离开

我们开始记录的时候可能已经有人在,求最小容量。

解:
我们记录当前已经进来了cur个人,in[x]表示x是否已进入
当+x,一个人进入时,in[x]=true, cur++, 若cur > ans, ans=cur
当-x,一个人离开时,若in[x],即这个人已记录进来了,cur–
若in[x]==false,表示这个人在开始记录前已进来,ans++
并标记这个人离开,in[x]=false

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func main() {
    var n int
    fmt.Scan(&n)

    in := make([]bool, 1000001, 1000001)
    cur := 0
    ans := 0

    bs := bufio.NewScanner(os.Stdin)
    bs.Split(bufio.ScanWords)
    for i := 0; i < n; i++ {
        bs.Scan()
        c := bs.Text()[0]
        bs.Scan()
        p, _ := strconv.Atoi(bs.Text())
        if c == '+' {
            in[p] = true
            cur++
            if ans < cur {
                ans = cur
            }
        } else {
            if in[p] == true {
                cur--
            } else {
                ans++
            }
            in[p] = false
        }
    }

    fmt.Println(ans)
}
  • T6(556B)

Examples
input
3
1 0 0
output
Yes
input
5
4 2 1 4 3
output
Yes
input
4
0 2 3 1
output
No

一个机器,有n个数(0 ~ n-1),按一次按钮,第一个数+1,第二个-1,第三个+1…, (0-1 = n-1, n-1 + 1 = 0)
问能不能按若干次按钮,使这些数变成0, 1, 2…
如第一个例子,
1,0,0 -> 2, 2, 1
2, 2, 1 -> 0, 1, 2

解:
1) 按n次后会回归初始状态,所以可以有O(n*n)方法,模拟n次按按钮操作
2) 可以确定第一个数需要按按钮次数,检测后面的数是否变成正确的数O(n)

代码(GO)

package main

import (
    "fmt"
)

func main() {
    var n int
    fmt.Scan(&n)

    an := make([]int, n, n)
    for i := 0; i < n; i++ {
        fmt.Scan(&an[i])
    }

    first := n - an[0]
    ans := true
    for i := 1; i < n; i++ {
        if i%2 != 0 {
            an[i] -= first
            an[i] += n
        } else {
            an[i] += first
        }
        if an[i]%n != i {
            ans = false
            break
        }
    }

    if ans {
        fmt.Println("Yes")
    } else {
        fmt.Println("No")
    }
}
  • T7(588B)

Examples
input
10
output
10
input
12
output
6

给定数n,寻找一个数x,满足:
1> n % x == 0
2> x % (i*i) != 0 (i = 1, 2…)

n可以分解为若干质数pi
则x = p1*p2*…*pk

package main

import (
    "fmt"
)

func main() {
    var n uint64
    fmt.Scan(&n)

    var i, ans uint64
    i = 2
    ans = 1
    for i*i <= n {
        if n%i == 0 {
            ans *= i
            for n%i == 0 {
                n /= i
            }
        }
        i++
    }

    if n > 1 {
        ans *= n
    }
    fmt.Println(ans)
}
  • T8(559A)
    Examples
    input
    1 1 1 1 1 1
    output
    6
    input
    1 2 1 2 1 2
    output
    13

给出6个数,组成一个内角都为120度的六边形(保证能组成),
求能分成多少个边长为1的正三角形。
如:
这里写图片描述

这里写图片描述

解:
可以拆分如下:
这里写图片描述

假设六条边为a1~a6, 则可构造一个边长为(a1+a2+a3)的正三角形,

import sys

an = list(map(int, sys.stdin.readline().split()))
ans = (an[0] + an[1] + an[2])*(an[0] + an[1] + an[2]) - an[0]*an[0] - an[2]*an[2] - an[4] * an[4]
print(ans)
  • T9(508A)
    Examples
    input
    2 2 4
    1 1
    1 2
    2 1
    2 2
    output
    4
    input
    2 3 6
    2 3
    2 2
    1 3
    2 2
    1 2
    1 1
    output
    5
    input
    5 3 7
    2 3
    1 2
    1 1
    4 1
    3 1
    5 3
    3 2
    output
    0

第一行n, m, k表示一个矩阵的行列,及操作步数,
后面k行x, y会把矩阵x, y位置置为1,若第x步,矩阵出现2x2方格数字都为1,则失败,
求第几步失败,若每失败输出0.

设置一个(n+2) * (m+2)的矩阵,逐步检测是否出现2*2都为1的方格。

代码(GO),二维切片

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
)

func is_lose(img [][]int, x, y int) bool {
    ret := false
    if img[x-1][y-1]+img[x-1][y]+img[x][y-1]+img[x][y] == 4 {
        ret = true
    } else if img[x-1][y+1]+img[x-1][y]+img[x][y+1]+img[x][y] == 4 {
        ret = true
    } else if img[x+1][y-1]+img[x+1][y]+img[x][y-1]+img[x][y] == 4 {
        ret = true
    } else if img[x+1][y+1]+img[x+1][y]+img[x][y+1]+img[x][y] == 4 {
        ret = true
    }

    return ret
}

/*
func dump(img [][]int, n, m int) {
    for i := 0; i < n+2; i++ {
        for j := 0; j < m+2; j++ {
            fmt.Printf("%d ", img[i][j])
        }
        fmt.Println()
    }
}
*/

func main() {
    var n, m, k int
    fmt.Scan(&n, &m, &k)

    img := [][]int{}
    for i := 0; i <= n+1; i++ {
        row := make([]int, m+2, m+2)
        img = append(img, row)
    }

    ans := 0
    bs := bufio.NewScanner(os.Stdin)
    bs.Split(bufio.ScanWords)
    for i := 0; i < k; i++ {
        bs.Scan()
        x, _ := strconv.Atoi(bs.Text())
        bs.Scan()
        y, _ := strconv.Atoi(bs.Text())

        img[x][y] = 1
        //dump(img, n, m)
        if is_lose(img, x, y) {
            ans = i + 1
            break
        }
    }

    fmt.Println(ans)
}
  • T10(219A)
    一个字符串s,若能分成k个完全相关的字符串,则称为k-string.
    如 “aabaabaabaab” 是1-string, 2-string, 4-string, 不是3-string, 5-string, 6-string…
    给一个字符串s和数字k,问修改s的顺序,是否可组成k-string.
    若能,输出字符串,否则输出-1
    Examples
    input
    2
    aazz
    output
    azaz
    input
    3
    abcabcabz
    output
    -1

解:
1)计数每个字母出现的个数
2)若一个字母出现x次,x不能整除k,则不能组成k-string,否则这个字符串将被分成k份,
每份有cnt/k个这个字母

package main

import (
    "fmt"
)

func solve(k int, s string) string {
    length := len(s)
    if length%k != 0 {
        return "-1"
    }

    counts := make([]int, 26, 26)
    for i := 0; i < length; i++ {
        counts[s[i]-'a']++
    }

    tmp := ""
    for i := 0; i < 26; i++ {
        if counts[i] == 0 {
            continue
        }
        if counts[i]%k != 0 {
            return "-1"
        }
        for j := 0; j < counts[i]/k; j++ {
            tmp += string(i + 'a')
        }
    }

    ans := ""
    for i := 0; i < length/len(tmp); i++ {
        ans += tmp
    }

    return ans
}

func main() {
    var k int
    fmt.Scan(&k)

    var s string
    fmt.Scan(&s)

    fmt.Println(solve(k, s))
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值