zoukankan      html  css  js  c++  java
  • Megcup 2017 决赛第一题 规则

    2017Megcup
    2017Megcup决赛第三题题解
    赛题评论

    只做出了一道题,虽然慢慢地退出了前128名,但还是要记录一下。
    10点钟开始,一看第一题很熟悉,因为研究过格点图中电流问题,其实就是求解线性方程组。上来就编,用Python,用numpy解方程,比较难于描述,编程水平也太差劲,好久不编手生得很。磨磨蹭蹭直到2:19才成功解决。这是排名90名左右,但是因为这道题做出来的人太多,也就不太值钱了,所以我一直在退步。以后也再没过题,直到比赛即将结束前的三四个小时,退出了前128名,榜上无名了。

    什么叫做能力?能力就是比赛时的状态,就看第一次遇到问题时的反应。人跟人的差距简直就是天壤之别。人与人之间智商的差距之悬殊,不亚于人与人体型大小之悬殊。想想那些2米多的大高个,想想1米七多点的自己。

    开始做第二题DogFood,我一开始觉得应该是暴力,枚举1e8个点,用python写,用sklearn的kdtree,结果太慢了,运行出结果大约需要5分钟,并且结果太不精确。我就想别人用的什么妙招。。。很纠结。
    直到比赛结束,看到一大群人都是暴力,就连求第k近邻都是暴力,没有使用KD树,只不过用的是C++,估计会快得多。真后悔没有用C++暴力一下。

    开始做Error++,这道题不会做,也没思路。就是瞎编

    林教主誓死要拿下锈规作图,我也开始看这道题。读Matrix大神博客,懂了,编不出来。知道第二天花了整整一天时间才怼出来了这道题。

    这次比赛的奖金分配、计分规则非常新颖,用一个图的形式形象的描述了分数的计算方式。
    这种计算方式有如下特点:

    • 一道题,做出来的人越少,这些人越能分到更多的流量
    • 流量延时,比赛结束之后,流量还在计算着,需要等10h之后再看积分

    解法:
    这个问题其实就是解线性方程组,每个结点的流入量与流出量相等。
    对于N个结点,分别对每个结点列方程,可以很容易列出N个线性方程来
    但是,这N个线性方程组的秩必然是N-1
    还要添加一个条件:各个节点的硬币之和为(人题数)
    我的做法是,不对中心节点列方程(毕竟它有一条自回路,处理略麻烦),添加“硬币之和”条件
    解此线性方程组即可

    这么简单的问题,我竟然做了将近4个半小时,真是老了
    转念一想,我年轻时也不咋地

    import math
    
    import numpy as np
    
    solved = [0] * 8  # 第i题解决的人数
    person_id_map = dict()  # 将人名映射到id
    data = []
    g = None  # 图136+9个结点
    gsize = None
    
    score = None  # 当前分数
    sum_score = None  # 分数积分
    
    
    # 构图
    def submit(person_id, q):
        solved[q] += 1
        for i in range(9, gsize):
            if g[q][i]:
                g[q][i] = 1 / solved[q]
        g[q][person_id] = 1 / solved[q]
        g[person_id][q] = 1
        g[8][q] += 1
        g[q][8] += 1 / solved[q]
    
    
    def getOutSum(pos):
        s = 0
        for i in range(gsize):
            s += g[pos][i]
        return s
    
    
    def equation():
        a, b = [], []
        # o表示各个结点流出流量之和
        o = [0] * gsize
        for i in range(gsize):
            o[i] = getOutSum(i)
        for i in range(gsize):
            if i == 8: continue
            if not o[i]: continue
            row = []
            for j in range(gsize):
                if not o[j]: continue
                if i == j:
                    row.append(1)
                else:
                    row.append(-g[j][i] / o[j])
            a.append(row)
            b.append(0)
        a.append([1] * len(a[0]))
        b.append(sum(solved))
        ans = np.linalg.solve(a, b)
        ansi = 0
        for i in range(gsize):
            if o[i]:
                score[i] = ans[ansi]
                ansi += 1
            else:
                score[i] = 0
    
    
    def accumulate(dt):
        for i in range(gsize):
            sum_score[i] += score[i] * dt
    
    
    def load():
        global gsize
        gsize = 9
        # 读入数据,处理
        for line in open("in.txt", encoding="utf8"):
            if not line: continue
            t, person, q = line.split()
            t = float(t)
            q = int(q)
            if person not in person_id_map:
                person_id_map[person] = gsize
                gsize += 1
            person_id = person_id_map[person]
            data.append((t, person_id, q))
    
    
    def init():
        global g, score, sum_score
        g = [[0 for _ in range(gsize)] for __ in range(gsize)]
        g[8][8] = 1
        score = [0] * gsize
        sum_score = [0] * gsize
    
    
    def people():
        ans = []
        for name, person_id in person_id_map.items():
            ans.append((name, sum_score[person_id]))
        ans.sort(key=lambda x: -x[1])
        return ans
    
    
    def main():
        for i in range(len(data)):
            if i > 0:
                accumulate(data[i][0] - data[i - 1][0])
            submit(data[i][1], data[i][2])
            equation()
        accumulate(3600 * 22 - data[len(data) - 1][0])
    
    
    def getStandard(a):
        sz = min(len(a), 32)
        mean = sum([a[i][1] for i in range(sz)]) / sz
        sq = sum([(a[i][1] - mean) ** 2 for i in range(sz)]) / sz
        return math.sqrt(sq)
    
    
    def output(a):
        s = getStandard(a)
        have_money = min(len(a), 32)
        percent = [math.exp(a[i][1] / s) for i in range(have_money)]
        sum_percent = sum(percent)
        for i in range(have_money):
            print(i + 1, a[i][0], a[i][1], 88888 * percent[i] / sum_percent)
        for i in range(have_money, min(128, len(a))):
            print(i + 1, a[i][0], a[i][1], 0)
    
    
    load()
    init()
    main()
    output(people())
    
  • 相关阅读:
    javascript入门 之 zTree(十四 增删查改)(二)
    javascript入门 之 zTree(十四 增删查改)(一)
    javascript入门 之 zTree(十三 移动/复制事件)
    javascript入门 之 bind() (二)
    javascript入门 之 zTree(十二 托拽事件(二))
    javascript入门 之 zTree(十一 托拽事件(一))
    Java 使用 switch 语句和枚举类型
    微信公众号开发(四)—— 自定义菜单的创建
    微信公众号开发(三)——获取 Access_Token
    微信公众号开发(二)—— 图文消息
  • 原文地址:https://www.cnblogs.com/weiyinfu/p/6622662.html
Copyright © 2011-2022 走看看