zoukankan      html  css  js  c++  java
  • 小贝_redis list类型学习

    redis  list类型

    一、查看list类型的命令

    二、list命令具体解释

     

     

    一、查看list类型的命令

    1、在终端数据 help @list

    127.0.0.1:6379>help @list

      BLPOP key [key ...] timeout

      summary: Remove and get the first element ina list, or block until one is ava

    ilable

      since: 2.0.0

     

      BRPOP key [key ...] timeout

      summary: Remove and get the last element in alist, or block until one is avai

    lable

      since: 2.0.0

     

      BRPOPLPUSH source destination timeout

      summary: Pop a value from a list, push it toanother list and return it; or bl

    ockuntil one is available

      since: 2.2.0

     

      LINDEX key index

      summary: Get an element from a list by itsindex

      since: 1.0.0

    ……

     

     

     

     

     

    二、list命令具体解释

    头元素和尾元素

    头元素指的是列表左端/前端第一个元素。尾元素指的是列表右端/后端第一个元素。

    举个样例,列表list包括三个元素:x, y, z,当中x是头元素。而z则是尾元素。

    空列表

    指不包括不论什么元素的列表。Redis将不存在的key也视为空列表。

     

    1、lpush

    lpush key value [value ...]

    将值value插入到列表key的表头。

    假设key不存在。一个空列表会被创建并运行lpush操作。

    当key存在但不是列表类型时,返回一个错误。

    时间复杂度:

    O(1)

    返回值:

    运行lpush命令后,表的长度。

    Note

    在Redis 2.3版本号曾经的lpush命令,都仅仅接受单个value值。

    127.0.0.1:6379>lpush word d

    (integer)1

    127.0.0.1:6379>lpush word a

    (integer)2

    127.0.0.1:6379>lpush word b

    (integer)3

    127.0.0.1:6379>lrange word 0 -1  # 显示列表内全部元素

    1)"b"

    2)"a"

    3)"d"

     

    2、lpushx

    lpushx key value

    将值value插入到列表key的表头,当且仅当key存在而且是一个列表。

    和lpush命令相反,当key不存在时。lpushx命令什么也不做。

    时间复杂度:

    O(1)

    返回值:

    lpushx命令运行之后。表的长度。

    #情况1:对空列表运行lpushx

    127.0.0.1:6379>llen greet    # greet是一个空列表

    (integer)0

    127.0.0.1:6379>lpushx greet "hello"  # 尝试lpushx。失败,由于列表为空

    (integer)0

    #情况2:对非空列表运行lpushx

    127.0.0.1:6379>lpush greet "hello"   # 先用lpush创建一个有一个元素的列表

    (integer)1

    127.0.0.1:6379>lpushx greet "good morning"   #这次lpushx运行成功

    (integer)2

    127.0.0.1:6379>lrange greet 0 -1

    1)"good morning"

    2)"hello"

     

    3、rpush

    rpush key value [value ...]

    将值value插入到列表key的表尾。

    假设key不存在。一个空列表会被创建并运行rpush操作。

    当key存在但不是列表类型时,返回一个错误。

    时间复杂度:

    O(1)

    返回值:

    运行rpush操作后,表的长度。

    Note

    在Redis 2.3版本号曾经的rpush命令,都仅仅接受单个value值。

    127.0.0.1:6379>llen fp-language # 显示列表中的元素数量

    (integer)0

    127.0.0.1:6379>rpush fp-language lisp

    (integer)1

    127.0.0.1:6379>lrange fp-language 0 0   # 显示列表中的元素

    1)"lisp"

    127.0.0.1:6379>rpush fp-language scheme

    (integer)2

    127.0.0.1:6379>lrange fp-language 0 1   # 显示列表中的元素

    1)"lisp"

    2)"scheme"

     

    4、rpushx

    rpushx key value

    将值value插入到列表key的表尾,当且仅当key存在而且是一个列表。

    和rpush命令相反,当key不存在时。rpushx命令什么也不做。

    时间复杂度:

    O(1)

    返回值:

    rpushx命令运行之后,表的长度。

    #情况1:key不存在

    127.0.0.1:6379>llen greet

    (integer)0

    127.0.0.1:6379>rpushx greet "hello"  # 对不存在的key进行rpushx,PUSH失败。

    (integer)0

    #情况2:key存在且是一个非空列表

    127.0.0.1:6379>rpush greet "hi"  # 先用rpush插入一个元素

    (integer)1

    127.0.0.1:6379>rpushx greet "hello"  # greet如今是一个列表类型。rpushx操作成功。

    (integer)2

    127.0.0.1:6379>lrange greet 0 -1

    1)"hi"

    2)"hello"

     

    5、lpop

    lpop key

    移除并返回列表key的头元素。

    时间复杂度:

    O(1)

    返回值:

    列表的头元素。

    当key不存在时,返回nil。

    127.0.0.1:6379>llen course

    (integer)0

    127.0.0.1:6379>rpush course algorithm001

    (integer)1

    127.0.0.1:6379>rpush course c++101

    (integer)2

    127.0.0.1:6379>LPOP course  # 移除头元素

    "algorithm001"

     

    6、rpop

    rpop key

    移除并返回列表key的尾元素。

    时间复杂度:

    O(1)

    返回值:

    列表的尾元素。

    当key不存在时,返回nil。

    127.0.0.1:6379>rpush mylist "one"

    (integer)1

    127.0.0.1:6379>rpush mylist "two"

    (integer)2

    127.0.0.1:6379>rpush mylist "three"

    (integer)3

    127.0.0.1:6379>rpop mylist  # 返回被弹出的元素

    "three"

    127.0.0.1:6379>lrange mylist 0 -1   # 列表剩下的元素

    1)"one"

    2)"two"

     

    7、rlpop

    rlpopkey [key ...] timeout

    rlpop是列表的堵塞式(blocking)弹出原语。

    它是LPOP命令的堵塞版本号,当给定列表内没有不论什么元素可供弹出的时候,连接将被rlpop命令堵塞,直到等待超时或发现可弹出元素为止。

    当给定多个key參数时,按參数key的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。

    非堵塞行为

    当rlpop被调用时,假设给定key内至少有一个非空列表,那么弹出遇到的第一个非空列表的头元素,并和被弹出元素所属的列表的名字一起,组成结果返回给调用者。

    当存在多个给定key时,rlpop按给定key參数排列的先后顺序,依次检查各个列表。

    如果如今有job、 command和request三个列表。当中job不存在,command和request都持有非空列表。考虑下面命令:

    rlpopjob command request 0

    rlpop保证返回的元素来自command。由于它是按”查找job -> 查找command -> 查找request“这种顺序。第一个找到的非空列表。

     

    127.0.0.1:6379>DEL job command request  # 确保key都被删除

    (integer)0

    127.0.0.1:6379>lpush command "update system..." # 为command列表添加一个值

    (integer)1

    127.0.0.1:6379>lpush request "visit page"  # 为request列表添加一个值

    (integer)1

    127.0.0.1:6379>rlpop job command request 0  # job列表为空。被跳过。紧接着command列表的第一个元素被弹出。

    1)"command"    # 弹出元素所属的列表

    2)"update system..."   # 弹出元素所属的值堵塞行为

    假设全部给定key都不存在或包括空列表。那么rlpop命令将堵塞连接。直到等待超时。或有还有一个client对给定key的随意一个运行lpush或rpush命令为止。

    超时參数timeout接受一个以秒为单位的数字作为值。超时參数设为0表示堵塞时间能够无限期延长(block indefinitely) 。

    127.0.0.1:6379>EXISTS job  # 确保两个key都不存在

    (integer)0

    127.0.0.1:6379>EXISTS command

    (integer)0

    127.0.0.1:6379>rlpop job command 300  #由于key一開始不存在,所以操作会被堵塞,直到还有一client对job或者command列表进行PUSH操作。

    1)"job"  # 这里被push的是job

    2)"do my home work"  # 被弹出的值

    (26.26s)  # 等待的秒数

    127.0.0.1:6379>rlpop job command 5  # 等待超时的情况

    (nil)

    (5.66s)# 等待的秒数同样的key被多个client同一时候堵塞

    同样的key能够被多个client同一时候堵塞。

    不同的client被放进一个队列中,按”先堵塞先服务”(first-rlpop,first-served)的顺序为key运行rlpop命令。

    在MULTI/EXEC事务中的rlpop

    rlpop能够用于流水线(pipline,批量地发送多个命令并读入多个回复)。但把它用在MULTI/EXEC块其中没有意义。由于这要求整个server被堵塞以保证块运行时的原子性。该行为阻止了其它client运行lpush或rpush命令。

    一个被包括在MULTI/EXEC块内的rlpop操作。行为表现得就像操作超时一样,只返回一个nil值。

    假设你是科幻迷。你能够想象在MULTI/EXEC块内。时间以无限的速度在流逝。

    127.0.0.1:6379>MULTI

    OK

    127.0.0.1:6379>rlpop job 30

    QUEUED

    127.0.0.1:6379>EXEC

    1)(nil)  # 操作没有等待,马上被返回了时间复杂度:

    O(1)

    返回值:

    假如在指定时间内没有不论什么元素被弹出,则返回一个nil和等待时长。

    反之,返回一个含有两个元素的列表。第一个元素是被弹出元素所属的key,第二个元素是被弹出元素的值。

     

    8、brpop

    brpopkey [key ...] timeout

    brpop是列表的堵塞式(blocking)弹出原语。

    它是rpop命令的堵塞版本号,当给定列表内没有不论什么元素可供弹出的时候。连接将被brpop命令堵塞,直到等待超时或发现可弹出元素为止。

    当给定多个key參数时,按參数key的先后顺序依次检查各个列表,弹出第一个非空列表的尾部元素。

    关于堵塞操作的很多其它信息,请查看rlpop命令,brpop除了弹出元素的位置和rlpop不同之外。其它表现一致。

    时间复杂度:

    O(1)

    返回值:

    假如在指定时间内没有不论什么元素被弹出。则返回一个nil和等待时长。

    反之。返回一个含有两个元素的列表,第一个元素是被弹出元素所属的key,第二个元素是被弹出元素的值。

    127.0.0.1:6379>llen course

    (integer)0

    127.0.0.1:6379>rpush course algorithm001

    (integer)1

    127.0.0.1:6379>rpush course c++101  # 尾部元素

    (integer)2

    127.0.0.1:6379>brpop course 30

    1)"course" # 弹出元素的key

    2)"c++101" # 弹出元素的值

     

    9、llen

    llenkey

    返回列表key的长度。

    假设key不存在,则key被解释为一个空列表,返回0.

    假设key不是列表类型,返回一个错误。

    时间复杂度:

    O(1)

    返回值:

    列表key的长度。

    #情况1:空列表

    127.0.0.1:6379>llen job

    (integer)0

    #情况2:非空列表

    127.0.0.1:6379>lpush job "cook food"

    (integer)1

    127.0.0.1:6379>lpush job "have lunch"

    (integer)2

    127.0.0.1:6379>llen job

    (integer)2

     

    10、lrange

    lrangekey start stop

    返回列表key中指定区间内的元素,区间以偏移量start和stop指定。

    下标(index)參数start和stop都以0为底,也就是说。以0表示列表的第一个元素。以1表示列表的第二个元素。以此类推。

    你也能够使用负数下标,以-1表示列表的最后一个元素,-2表示列表的倒数第二个元素,以此类推。

    注意lrange命令和编程语言区间函数的差别

    假如你有一个包括一百个元素的列表,对该列表运行lrange list 0 10,结果是一个包括11个元素的列表,这表明stop下标也在lrange命令的取值范围之内(闭区间)。这和某些语言的区间函数可能不一致,比方Ruby的Range.new、Array#slice和Python的range()函数。

    超出范围的下标

    超出范围的下标值不会引起错误。

    假设start下标比列表的最大下标end(llen list减去1)还要大,或者start > stop,lrange返回一个空列表。

    假设stop下标比end下标还要大,Redis将stop的值设置为end。

    时间复杂度:

    O(S+N),S为偏移量start。N为指定区间内元素的数量。

    返回值:

    一个列表,包括指定区间内的元素。

    127.0.0.1:6379>rpush fp-language lisp   # 插入一个值到列表fp-language

    (integer)1

    127.0.0.1:6379>lrange fp-language 0 0

    1)"lisp"

    127.0.0.1:6379>rpush fp-language scheme

    (integer)2

    127.0.0.1:6379>lrange fp-language 0 1

    1)"lisp"

    2)"scheme"

     

    11、lrem

    lremkey count value

    依据參数count的值。移除列表中与參数value相等的元素。

    count的值能够是下面几种:

    count> 0: 从表头開始向表尾搜索。移除与value相等的元素,数量为count。

    count< 0: 从表尾開始向表头搜索,移除与value相等的元素。数量为count的绝对值。

    count= 0: 移除表中全部与value相等的值。

    时间复杂度:

    O(N),N为列表的长度。

    返回值:

    被移除元素的数量。

    由于不存在的key被视作空表(empty list)。所以当key不存在时。lrem命令总是返回0。

    #先创建一个表,内容排列是

    #morning hello morning helllo morning

    127.0.0.1:6379>lpush greet "morning"

    (integer)1

    127.0.0.1:6379>lpush greet "hello"

    (integer)2

    127.0.0.1:6379>lpush greet "morning"

    (integer)3

    127.0.0.1:6379>lpush greet "hello"

    (integer)4

    127.0.0.1:6379>lpush greet "morning"

    (integer)5

     

    127.0.0.1:6379>lrange greet 0 4 # 查看全部元素

    1)"morning"

    2)"hello"

    3)"morning"

    4)"hello"

    5)"morning"

     

    127.0.0.1:6379>lrem greet 2 morning  # 移除从表头到表尾,最先发现的两个morning

    (integer)2  # 两个元素被移除

     

    127.0.0.1:6379>llen greet   # 还剩3个元素

    (integer)3

     

    127.0.0.1:6379>lrange greet 0 2

    1)"hello"

    2)"hello"

    3)"morning"

     

    127.0.0.1:6379>lrem greet -1 morning  # 移除从表尾到表头,第一个morning

    (integer)1

     

    127.0.0.1:6379>llen greet

    (integer)2

     

    127.0.0.1:6379>lrange greet 0 1

    1)"hello"

    2)"hello"

     

    127.0.0.1:6379>lrem greet 0 hello  # 移除表中全部hello

    (integer)2  # 两个hello被移除

     

    127.0.0.1:6379>llen greet

    (integer)0

     

    12、lset

    lsetkey index value

    将列表key下标为index的元素的值甚至为value。

    很多其它信息请參考lindex操作。

    当index參数超出范围时。返回一个错误。

    时间复杂度:

    对头元素或尾元素进行lset操作。复杂度为O(1)。

    其它情况下。为O(N)。N为列表的长度。

    返回值:

    操作成功返回ok,否则返回错误信息。

    127.0.0.1:6379>lpush job "cook food"

    (integer)1

    127.0.0.1:6379>lrange job 0 0

    1)"cook food"

    127.0.0.1:6379>lset job 0 "play game"

    OK

    127.0.0.1:6379>lrange job  0 0

    1)"play game"

     

    13、ltrim

    ltrimkey start stop

    对一个列表进行修剪(trim),就是说,让列表仅仅保留指定区间内的元素,不在指定区间之内的元素都将被删除。

    举个样例,运行命令ltrim list 0 2,表示仅仅保留列表list的前三个元素,其余元素所有删除。

    下标(index)參数start和stop都以0为底,也就是说,以0表示列表的第一个元素,以1表示列表的第二个元素,以此类推。

    你也能够使用负数下标。以-1表示列表的最后一个元素,-2表示列表的倒数第二个元素,以此类推。

    当key不是列表类型时,返回一个错误。

    ltrim命令通常和lpush命令或rpush命令配合使用。举个样例:

    lpushlog newest_log

    ltrimlog 0 99这个样例模拟了一个日志程序,每次将最新日志newest_log放到log列表中。而且仅仅保留最新的100项。

    注意当这样使用ltrim命令时,时间复杂度是O(1),由于平均情况下,每次仅仅有一个元素被移除。

    注意ltrim命令和编程语言区间函数的差别

    假如你有一个包括一百个元素的列表list,对该列表运行ltrim list 0 10。结果是一个包括11个元素的列表。这表明stop下标也在ltrim命令的取值范围之内(闭区间),这和某些语言的区间函数可能不一致,比方Ruby的Range.new、Array#slice和Python的range()函数。

    超出范围的下标

    超出范围的下标值不会引起错误。

    假设start下标比列表的最大下标end(llen list减去1)还要大,或者start > stop,ltrim返回一个空列表(由于ltrim已经将整个列表清空)。

    假设stop下标比end下标还要大。Redis将stop的值设置为end。

    时间复杂度:

    O(N)。N为被移除的元素的数量。

    返回值:

    命令运行成功时,返回ok。

    #情况1:普通情况下标

    127.0.0.1:6379>lrange alpha 0 -1 # 建立一个5元素的列表

    1)"h"

    2)"e"

    3)"l"

    4)"l"

    5)"o"

     

    127.0.0.1:6379>ltrim alpha 1 -1  # 删除索引为0的元素

    OK

    127.0.0.1:6379>lrange alpha 0 -1 # "h"被删除

    1)"e"

    2)"l"

    3)"l"

    4)"o"

    #情况2:stop下标比元素的最大下标要大

    127.0.0.1:6379>ltrim alpha 1 10086

    OK

    127.0.0.1:6379>lrange alpha 0 -1

    1)"l"

    2)"l"

    3)"o"

    #情况3:start和stop下标都比最大下标要大,且start < sotp

    127.0.0.1:6379>ltrim alpha 10086 200000

    OK

    127.0.0.1:6379>lrange alpha 0 -1 # 整个列表被清空,等同于DEL alpha

    (emptylist or set)

    #情况4:start > stop

    127.0.0.1:6379>lrange alpha 0 -1 # 在新建一个列表

    1)"h"

    2)"u"

    3)"a"

    4)"n"

    5)"g"

    6)"z"

    127.0.0.1:6379>ltrim alpha 10086 4

    OK

    127.0.0.1:6379>lrange alpha 0 -1 # 列表相同被清空

    (emptylist or set)

     

    14、lindex

    lindexkey index

    返回列表key中,下标为index的元素。

    下标(index)參数start和stop都以0为底,也就是说。以0表示列表的第一个元素,以1表示列表的第二个元素,以此类推。

    你也能够使用负数下标。以-1表示列表的最后一个元素,-2表示列表的倒数第二个元素,以此类推。

    假设key不是列表类型,返回一个错误。

    时间复杂度:

    O(N),N为到达下标index过程中经过的元素数量。

    因此,对列表的头元素和尾元素运行lindex命令。复杂度为O(1)。

    返回值:

    列表中下标为index的元素。

    假设index參数的值不在列表的区间范围内(out of range)。返回nil。

    127.0.0.1:6379>lpush mylist "World"

    (integer)1

    127.0.0.1:6379>lpush mylist "Hello"

    (integer)2

    127.0.0.1:6379>lindex mylist 0

    "Hello"

    127.0.0.1:6379>lindex mylist -1

    "World"

    127.0.0.1:6379>lindex mylist 3  # index不在mylist的区间范围内

    (nil)

     

    15、linsert

    linsertkey BEFORE|AFTER pivot value

    将值value插入到列表key其中。位于值pivot之前或之后。

    当pivot不存在于列表key时,不运行不论什么操作。

    当key不存在时,key被视为空列表,不运行不论什么操作。

    假设key不是列表类型,返回一个错误。

    时间复杂度:

    O(N),N为寻找pivot过程中经过的元素数量。

    返回值:

    假设命令运行成功。返回插入操作完毕之后,列表的长度。

    假设没有找到pivot。返回-1。

    假设key不存在或为空列表,返回0。

    127.0.0.1:6379>rpush mylist "Hello"

    (integer)1

    127.0.0.1:6379>rpush mylist "World"

    (integer)2

    127.0.0.1:6379>linsert mylist BEFORE "World" "There"

    (integer)3

    127.0.0.1:6379>lrange mylist 0 -1

    1)"Hello"

    2)"There"

    3)"World"

    127.0.0.1:6379>linsert mylist BEFORE "go" "let's"    # 对一个非空列表插入,查找一个不存在的pivot

    (integer)-1    # 失败

    127.0.0.1:6379>EXISTS fake_list  # 对一个空列表运行linsert命令

    (integer)0

    127.0.0.1:6379>linsert fake_list BEFORE "nono" "gogogog"

    (integer)0 # 失败

     

    16、rpoplpush

    rpoplpushsource destination

    命令rpoplpush在一个原子时间内,运行下面两个动作:

    将列表source中的最后一个元素(尾元素)弹出。并返回给client。

    将source弹出的元素插入到列表destination,作为destination列表的的头元素。

    举个样例,你有两个列表source和destination,source列表有元素a, b, c,destination列表有元素x, y, z,运行rpoplpush source destination之后,source列表包括元素a, b。destination列表包括元素c, x, y, z 。而且元素c被返回。

    假设source不存在,值nil被返回,而且不运行其它动作。

    假设source和destination同样,则列表中的表尾元素被移动到表头。并返回该元素。能够把这样的特殊情况视作列表的旋转(rotation)操作。

    时间复杂度:

    O(1)

    返回值:

    假如在指定时间内没有不论什么元素被弹出,则返回一个nil和等待时长。

    反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。

    #相关数据

    127.0.0.1:6379>rpush alpha a

    (integer)1

    127.0.0.1:6379>rpush alpha b

    (integer)2

    127.0.0.1:6379>rpush alpha c

    (integer)3

    127.0.0.1:6379>rpush alpha d

    (integer)4

     

    #情况1:source和destination不同

    127.0.0.1:6379>lrange alpha 0 -1 # 查看全部元素

    1)"a"

    2)"b"

    3)"c"

    4)"d"

    127.0.0.1:6379>rpoplpush alpha reciver   # 运行一次rpoplpush看看

    "d"

    127.0.0.1:6379>lrange alpha 0 -1

    1)"a"

    2)"b"

    3)"c"

    127.0.0.1:6379>lrange reciver 0 -1

    1)"d"

    #情况2:source和destination同样

    127.0.0.1:6379>rpoplpush alpha alpha

    "c"

    127.0.0.1:6379>lrange alpha 0 -1 # 原来的尾元素"c"被放到了头部

    1)"c"

    2)"a"

    3)"b"

     

    设计模式:一个安全的队列

    Redis的列表常常被用作队列(queue)。用于在不同程序之间有序地交换消息(message)。

    一个程序(称之为生产者,producer)通过lpush命令将消息放入队列中。而还有一个程序(称之为消费者,consumer)通过rpop命令取出队列中等待时间最长的消息。

    不幸的是,在这个过程中,一个消费者可能在获得一个消息之后崩溃,而未运行完毕的消息也因此丢失。

    使用rpoplpush命令能够解决问题,由于它在返回一个消息之余,还将该消息加入到还有一个列表其中,另外的这个列表能够用作消息的备份表:假如一切正常,当消费者完毕该消息的处理之后,能够用lrem命令将该消息从备份表删除。

    还有一方面,助手(helper)程序能够通过监视备份表,将超过一定处理时限的消息又一次放入队列中去(负责处理该消息的消费者可能已经崩溃),这样就不会丢失不论什么消息了。

     

    17、brpoplpush

    brpoplpushsource destination timeout

    brpoplpush是rpoplpush的堵塞版本号,当给定列表source不为空时。brpoplpush的表现和rpoplpush一样。

    当列表source为空时,brpoplpush命令将堵塞连接,直到等待超时,或有还有一个client对source运行lpush或rpush命令为止。

    超时參数timeout接受一个以秒为单位的数字作为值。

    超时參数设为0表示堵塞时间能够无限期延长(block indefinitely) 。

    很多其它相关信息,请參考rpoplpush命令。

    时间复杂度:

    O(1)

    返回值:

    假如在指定时间内没有不论什么元素被弹出,则返回一个nil和等待时长。

    反之,返回一个含有两个元素的列表。第一个元素是被弹出元素的值。第二个元素是等待时长。

    #情况1:非空列表

    127.0.0.1:6379>brpoplpush msg reciver 500

    "hellomoto"    # 弹出元素的值

    (3.38s)         # 等待时长

    127.0.0.1:6379>llen reciver

    (integer)1

    127.0.0.1:6379>lrange reciver 0 0

    1)"hello moto"

    #情况2:空列表

    127.0.0.1:6379>brpoplpush msg reciver 1

    (nil)

    (1.34s)

  • 相关阅读:
    「SOL」开关(LOJ)
    「SOL」星际迷航(LOJ)
    「NOTE」概率生成函数
    「SOL」谢特(LOJ)
    「SOL」重建计划(BZOJ)
    「SOL」Tug of War(洛谷)
    「SOL」同余方程(LOJ)
    「SOL」Bad Cryptography(Codeforces)
    「SOL」小A与两位神仙(洛谷)
    「SOL」Social Distance(AtCoder)
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/7082249.html
Copyright © 2011-2022 走看看