codeforces April fool contest 2017

r_64 posted @ 2017年8月12日 09:37 in 未分类 , 1789 阅读

提示:这篇文章的主题是code-golf(即写出尽可能短的代码),使用的语言是Python 2。这篇文章含有cf April Fool contest 2017的剧透。

至于为什么cf3月底的比赛现在才更呢。。因为现在闲的蛋疼嘛,cc太水了早就ak了没事做>_>

注:文章中的submission是截止发表日期(2017.8.12)的,“rank1的Ruby/Python代码”也是指截止2017.8.12时的rank1。

A.Numbers Joke

这题真没什么好说的,oeis上有数列(A006753),然后打下来即可。

rank1的ruby党就是把数列编码成Unicode了。。

因为当成一个codegolf题的话这题太无聊了,所以我就没写了>_>

B.Kids' Riddle

题解:转成16进制看有几个0。第一次提交是这样的,一看就不是合格的codegolfer。

def f(i) : return i in ['4','6','8','9','0','a','b','d']
def g(i) : return i in ['8','b']
print sum([f(i)+g(i) for i in hex(int(raw_input()))])-1

注意那个-1是因为hex()的返回值中有"0x"这个前缀,而0对答案是有$1$的贡献的。

然后显然可以把i in ['4','6',...]改成i in "46...",这样就省了一堆字节。

print sum([(i in'46890abd')+(i in'8b')for i in hex(int(raw_input()))])-1

然后居然比ruby代码要短,当上了rank2。

rank1的python代码用了count函数,比我还是不知道高到哪去了。(下面的代码是我改进了一下rank1的。。现在我是rank1了>_>

print sum(["046889abbd".count(x)for x in hex(int(input()))])-1

C.INTERCALC

求数列最大值与最后一项的异或。

首先对于python来说,输入的数列长度是没必要的,就把它丢掉了。然后代码长这样:

input()
print (lambda x:max(x)^x[len(x)-1])(map(int,raw_input().split()))

啊。。发现x[len(x)-1]可以简写为x[-1],就又省了几个字节:

input()
print (lambda x:max(x)^x[-1])(map(int,raw_input().split()))

做完D题之后发现lambda是我自作多情了,最裸的写法就可以再省$10$个字节。。。

input();x=map(int,raw_input().split());print max(x)^x[-1]

行吧。。我还是naive了啊。。新手golfer也不容易啊。。。

D.Touchy-Feely Palindromes

将数字串转成Braille(盲文)之后是回文串。

print ["No","Yes"][(lambda x:min([x[i]+x[::-1][i]in["33","46","59","77","80","64","95","08"]for i in range(len(x))]))(raw_input())]

这段代码是什么意思呢,就是x的第i位和对称的那一位必须是这几个组合中的某一个。例如说x的某一位是8,那么其对称位必须是0,因为80在Braille中是镜像的关系。

那个["No","Yes"][]的trick是我思考了一会弄出来的。本来打算用三目运算符,但是python的三目是b if a else c长得要死就改成了[b,c][a]

然后那个字符串列表好长啊。。于是改了一下

print["No","Yes"][(lambda x:min([x[i]+x[::-1][i]in"33 46 59 77 80 64 95 08".split()for i in range(len(x))]))(raw_input())]

这个字符串还可以改进。比如说5995显然写成595也是没问题的还能少$1$个字节。

print["No","Yes"][(lambda x:min(["33.464.595.808.77".count(x[i]+x[::-1][i])for i in range(len(x))]))(raw_input())]

接下来要干掉那个for i in range(len(x))rangelen连用长成狗!作为python小白我就开始查文档,查stackoverflow。。终于查到一个enumerate语法,它的意思是枚举(i,x[i])这个pair。啊对了,x[::-1][i]有$10$个字节呢,为什么不改成x[-1-i]呢(x[-a]表示倒数第a位)。

print["No","Yes"][(lambda x:min(["33.464.595.808.77".count(b+x[-a-1])for a,b in enumerate(x)]))(raw_input())]

然后我发现lambda是多此一举。。x=raw_input();(lambda x:)(raw_input())不知道短到哪里去了。顺便count也是我脑抽了,B题的rank1大佬用count是因为答案可能有$2$,而这里答案顶多是$1$。

x=raw_input();print["No","Yes"][min([b+x[-a-1]in"33.464.595.808.77"for a,b in enumerate(x)])]

这样就缩到小于100B了。

目前排名rank2,rank1的ruby大爷应该是无法超越的吧。他的写法是将x的每一位换成对应的镜像,再看等不等于其反串。python有对应的语法,但是反而更长了(需要包含string库,方法的名称也长成狗)。下面是rank1代码

s=gets.chomp
puts s==s.reverse.tr('1234567890','##36947058')?:Yes: :No

对应的python代码

from string import *
s=raw_input();print["No","Yes"][s.translate(maketrans("12465980","r_649508"))==s[::-1]]

E.Twisted Circuit

要么计算这个电路,要么把它打表打出来。我选择了后者。先写一个裸的。

import sys
u=int(''.join(sys.stdin.read(9).split()),2)
print int(u in [8,12,14,1,9,3,11,15])

表显然可以写的更短。

import sys
u=int(''.join(sys.stdin.read(9).split()),2)
print 56074>>u&1

接下来看读入能不能更短一点。试验发现cf上的换行符是'\n',就可以用replace了。再把读入嵌进输出就好。

import sys
print 56074>>(int(sys.stdin.read(9).replace('\n',''),2))&1

一些小改动省了$3$字节。。

import sys
print 56074>>int(sys.stdin.read().replace('\n',''),2)&1

然后没忍住看了一下rank2的python代码。。直接用input来读取数据(input()读一个数返回的就是这个数,不是字符串),妙,实在是妙。

I=input
a,b,c,d=I(),I(),I(),I()
print (a^b)&(c|d)^((b&c)|(a^d))

F.Crunching Numbers Just For You

这题要做两件事:一是排序,二是拖时间(用户要求程序运行时间为$1\mathtt{s}$到$2\mathtt{s}$之间)。

以下是第一发提交(就排到了rank3

print ' '.join(map(str,sorted(map(int,raw_input().split()[1:]))))
a=1e7
while a:a-=1

然后发现了一个(某种意义上)不需要在strint之间转来转去的方法,可以少$10$字节。轻松rank1。

print' '.join(sorted(raw_input().split()[1:],key=int))
a=1e7
while a:a-=1

G.BF Calculator

下面是考场代码,把结果一位一位输出。

cur = 0
def gao(x) :
    global cur
    if cur < x :
        print '+'*(x-cur) + '.'
    else :
        print '-'*(cur-x) + '.'
    cur = x
s=eval(raw_input())
for i in str(s) : gao(ord(i))

缩了一下变成这样。话说python中,字符串*负数=空串,这为缩代码带来了极大便利。

c=0
for i in str(input()):x=ord(i);print'+'*(x-c)+'-'*(c-x)+'.';c=x

又想了想可以换一种做法。每次输出一个字符然后移到一个新的地方输出另一个。少用两个变量。

for i in str(input()):print'+'*ord(i)+'.>'

拿到了跟一堆人的并列rank2。rank1又是ruby。>_>

最后

战况:

题号 A B C D E F G
排名(全部) 没做 2 并列第4 2 4 1 并列第2
排名(Python) 没做 2 并列第1 1 3 1 并列第1

好无聊啊


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter