1、小红的精灵
小红有 个精灵,精灵分布在 个房间中,第 个精灵可以施展 次魔法,现在有 个敌人要攻击,每次攻击需要一个房间的精灵都消耗一次魔法,该次攻击可以击杀一个敌人。问小红最多可以消灭多少敌人。
输入
一行三个整数 ,分别表示精灵数量,房间数量,敌人数量。
接下来 行,每行两个整数,第 行表示第 个精灵的所在房间编号 和可以施展的魔法次数 。
输出
输出一个整数,表示最多可以消灭的敌人数量。
样例
1 2 3 4 5 6 7 8 9 10 11 12 输入: 4 5 12 2 4 5 2 3 6 2 3 输出: 11 提示: 有12个敌人,第二个房间可以消灭3个敌人,第三个房间可以消灭6个敌人,第五个房间可以消灭2个敌人。总共可以消灭11个敌人。
解答
如果第 个房间没有精灵,那么第 个房间并没有用处。如果第 个房间有精灵,那么这个房间可以击败的敌人数为 。
最终把 的值进行求和即可,并和 取较小值。如果第 个房间没有精灵,那么令 。
代码
1 2 3 4 5 6 7 8 n, m, k = map (int , input ().split()) mp = {} INF = 10 ** 9 for _ in range (n): b, a = map (int , input ().split()) mp[b] = min (mp.get(b, INF), a) ans = min (sum (mp.values()), k) print (ans)
2、小红分糖果
小红有 个糖果,要分给小朋友,每个小朋友必须分到 个,如果可以分完,输出最少可以分给多少小朋友,最多可以分给多少小朋友,如果不能分完,输出 。
输入
一行三个整数 ,表示糖果数量和每个小朋友的要求。
输出
如果可以分完,输出最少可以分给多少小朋友,最多可以分给多少小朋友,如果不能分完,输出 。
样例
1 2 3 4 5 6 7 8 输入: 10 2 3 输出: 4 5 提示: 最少可以分给4个小朋友,[2,2,3,3]; 最多可以分给5个小朋友,每个小朋友分到2个糖果。
解答
假设现在需要求最大值,基本思想是每个小朋友都分的最少。也就是说,分得 个小朋友,还剩下 个糖果。容易知道 是答案的一个上界, 不能够再大了。可见 ,那么这些多出来的 个糖果需要分配回去,但是为了确保满足题意,哪怕分回去每个小朋友也不能分超过 个糖果,他们现在最多只能再得到 个糖果。因此,剩下的糖果数 必须满足 。如果不满足 ,
那么如果分给 个小朋友不可行,有没有可能通过减少小朋友从而获得一个分配方案呢?答案是不可能的,因为减少了小朋友后,就要承担原本分给他的 个糖果,之前的小朋友反而还需要多承受一些糖果(总共剩余不止 糖果了)。因此减少小朋友并不能获得一个合法的分配方案,上面给出的答案就是最佳答案。
假设现在需要求最小值,思想和上面的类似,每个小朋友都分的最多。也就是说,分得 个小朋友,还剩下 个糖果。容易知道 是答案的一个下界, 不能够再小了。类似的,可见 。如果 ,那么这些糖果恰好分完,不需要再判断其它情况。如果 ,那么还需要多一个小朋友来承受这些糖果。如果 ,那么说明这时新的小朋友已经满足了条件,此时答案为 ,如果 ,那么前面的小朋友只能都拿出 个糖果给他。因此,如果 仍然成立,那么这个小朋友也是符合条件的,否则他无法取到 个糖果,并不可行。
同样的问题,如果分给 个小朋友不可行,有没有可能通过增加小朋友从而获得一个分配方案呢?答案同样也是不可行的,因为增加了小朋友后,其余的小朋友就要拿出更多的糖果分出来,原来已经不够分配给持有 个糖果的小朋友的数量,现在更加不可行。因此增加小朋友并不能获得一个合法的分配方案,上面给出的答案就是最佳答案。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 n, l, r = map (int , input ().split()) rp, rr = divmod (n, l) if rp * (r - l) < rr: rp = -1 lp, lr = divmod (n, r) if lr > 0 : if lp * (r - l) + lr < l: lp = -1 else : lp += 1 if rp == -1 : print (-1 ) else : print (lp, rp)
3、小红的树上游走
小红有一棵 个节点的树,节点编号为 到 。每条边有一个权值,权值是 或者 。
对于一个长度为 的节点序列 ,按照顺序依次访问这些节点,从 走到 ,会按照最短路径走。
小红想知道,对于所有长度为 的节点序列中(一共有 个长度为 的序列),有多少个序列满足:小红走完这个序列后,经过的所有边的权值之和不为 0。
由于答案可能很大,你只需要输出答案对 取模的结果。
注意,小红可以从一个节点走到它自己,也可以重复经过一条边。
输入
一行两个整数 和 ,表示树的节点数和序列长度。
接下来 行,每行三个整数 ,表示节点 和节点 之间有一条边,权值为 。
输出
输出一个整数,表示满足条件的序列个数对 取模的结果。
样例
1 2 3 4 5 6 7 8 9 10 输入: 3 2 1 2 1 2 3 0 输出: 4 提示: 四个序列分别为[1,2],[2,1],[1,3],[3,1]
解答
这道题的对立问题是:有多少序列,经过的所有边的权值之和等于 。最终用总方案数 减去对立问题的答案数,就能过得到原问题的答案。
可以发现,求解对立问题的解比求解原问题要简单的多,只要序列 相邻的两个节点之间的路径都为 即可。原问题与此的区别在于, 中至少 存在一对相邻节点,其路径权值和不等于 ,由于还要考虑其它相邻对节点是否满足这个情况,因此直接求解原问题比较困难。
接下来求解这个对立问题。可见,只需要每一对相邻对节点的路径和为 即可,这时不需要考虑其它相邻节点对的问题,比较简单,我们使用并查集进行解决。将所有权值为 的所有边的相邻节点合并在一起,那么节点 和节点 的路径之和为 当且仅当它们在同一个集合中。因此,一个满足对立问题的序列,要求它的所有结点都在同一个集合中。假设所有合并操作完成后,一共有 个集合,第 个集合一共有 个节点,那么这个集合中,满足的节点序列答案为 。因此本题的最终答案为 。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 n, k = map (int , input ().split()) fa = [i for i in range (n)] sz = [1 for _ in range (n)] mod = 10 ** 9 + 7 def find (x ): if fa[x] == x: return x fa[x] = find(fa[x]) return fa[x] def merge (x, y ): u, v = find(x), find(y) if u != v: fa[v] = u sz[u] += sz[v] for _ in range (n - 1 ): x, y, w = map (int , input ().split()) x, y = x - 1 , y - 1 if w == 0 : merge(x, y) ans = (pow (n, k, mod) - sum (pow (sz[i], k, mod) for i in range (n) if i == find(i))) % mod print (ans)