小米 Online Judge 18年12月常规赛题解
小米兔跳格子
描述
米兔爸爸为了让小米兔好好锻炼身体,便给小米兔设置了一个挑战——跳格子。
要吃到自己心爱的胡萝卜,小米兔需要跳过面前一些格子。现有 NN 个格子,每个格子内都写上了一个非负数,表示当前最多可以往前跳多少格,胡萝卜就放在最后一个格子上。米兔开始站在第 1 个格子,试判断米兔能不能跳到最后一个格子吃到胡萝卜呢?
输入
输入为 NN 个数字 (N \lt 10N<10),用空格隔开,第 ii 个数字 s_isi (0 \le s_i \lt 100≤si<10) 表示米兔站在第 ii 个格子上时,最多能往前跳的格数。
输出
若米兔能跳到最后一个格子上吃到胡萝卜,输出 “true“,否则输出 “false“
输入样例
2 0 1 0 0 3 4
输出样例
false
题解
贪婪算法(推荐)
因为此题要判断米兔是否能到达最后一个位置,所以我们关心的只是米兔是否能到达最后一个位置,不需要
去关心每一个位置上剩余的步数。我们定义一个变量maxDistance,表示当前米兔最远能到达的位置,初始
值为0,然后遍历每一个格子,当maxDistance小于当前的格子下标,则说明米兔不能到达当前这个格子,更
不能到达最后一个格子吃到胡萝卜;当maxDistance大于等于一个格子到最后一个格子的距离,说明米兔可
以到达;否则更新maxDistance的值,maxDistance=max(maxDistance, i+nums[i]),(i为当前格子下标,
nums[i]表示此时米兔最多可以跳的格子数)。
code
public class Main {
public String solution(int[] nums) {
int maxDistance = 0;
for(int i = 0; i < nums.length; i++) {
if(i > maxDistance || maxDistance >= nums.length) break;
maxDistance = Math.max(i + nums[i], maxDistance);
}
return (maxDistance >= nums.length-1) + "";
}
}
数数字游戏
描述
小爱和小冰是一对好闺蜜,她们都是世界上最聪明的人工智能之一。某一天,他们俩一起玩数数字游戏,规则如下:
- 首先小爱和小冰各说一个目标数字num1num1,num2num2;
- 小爱和小冰轮流报数(小冰报数方法与小爱相同),每次只报一个数,报数者可以选择将这个数报给谁;
- 小爱先开始报数字,把这个数给自己或小冰都行,小爱和小冰各自得到的所有数之和不能超过自己的目标数字;
- 最终,谁再也报不出符合条件的数字谁就算输,另一个人就赢(即谁报完数后,两人所得数字之和都达到了各自的目标数字,谁就赢);
- 由于两人智商都是非常的高,所以觉得游戏太简单了,于是两人决定每次报的数只能是斐波那契数列中的元素(例如每次取1,2,3,5,8.......) 。
现在两人各说一个目标数字后请你判断谁会赢。如果小爱赢则输出"Xiaoai Win"
,反之小冰赢输出"Xiaobing Win"
。两人都很聪明,都会使用最优策略(每次报数是最优的)。
规定:斐波那契数列F(1)=1,F(2)=2,F(N)=F(N-1)+F(N-2)F(1)=1,F(2)=2,F(N)=F(N−1)+F(N−2)
输入
两个正整数,用空格隔开,分别表示小爱和小冰的目标数字num1num1,num2num2。
数据范围:num1,num2 < =10000num1,num2<=10000
输出
输出 "Xiaoai Win" 或 "Xiaobing Win",分别表示小爱赢或小冰赢。
输入样例
1 4
3 4
4 4
1 5
输出样例
Xiaoai Win
Xiaoai Win
Xiaobing Win
Xiaobing Win
题解
典型的SG 函数问题。可选步数为一系列不连续的数(斐波那契数),可用getSG 函数求得,最终结果是两
个目标数字的所有SG 值异或的结果 。
#include<stdio.h>
#include<string.h>
int sg[10005],vis[10005];
int get_sg(int n){
int f[21]={0,1,2,3,5,8,13,21,34,55,89,144,233,
377,610,987,1597,2584,4181,6765,10946};
memset(sg,0,(n+1)*sizeof(int));
for(int i=1; i<=n; i++){
memset(vis,0,(n+1)*sizeof(int));
for(int j=1; f[j]<=i; j++)
vis[sg[i-f[j]]]=1;
for(int j=0; j<=n; j++)
if(vis[j]==0){
sg[i]=j;
break;
}
}
return sg[n];
}
int main(){
int num1,num2,m;
while(scanf("%d%d",&num1,&num2)!=-1){
m=0;
m^=get_sg(num1);
m^=get_sg(num2);
printf(m?"Xiaoai Win\n":"Xiaobing Win\n");
}
return 0;
}
MMD
描述
Miku Miku Dance,简称 MMD, 是一款 3D 拟真舞蹈动画制作工具。
Nishikino Curtis 现在接到了一项任务,要制作一段舞蹈。
舞蹈由若干条线段组成,每条线段会有一个优美度 v_ivi。Nishikino Curtis 会以某种顺序遍历所有的线段。注意,只有走完整条线段后,她才会走下一条线段,并且不会再走已经完整走过的线段。每走完一条线段,就能获得该线段对应的优美度。
如果 Nishikino 走过的线段 l_ili,l_jlj 有交,且 v_i > v_jvi>vj,且 Nishikino 先走过了 l_ili,紧接着又走过了 l_jlj,那么就会获得 (v_i + v_j) \times \lfloor \frac{i + j}{2} \rfloor(vi+vj)×⌊2i+j⌋ 的额外优美度。
请你决定 Nishikino 的遍历顺序,最大化优美度之和,包括固定的优美度,和额外的优美度。
数据范围: n \le 300, v_i \le 1000n≤300,vi≤1000,所有坐标的绝对值 \le 10 ^ 6≤106。
输入
输入分为两部分:
第 1 部分为一个整数 nn,表示线段的数量;
第 2 部分为 nn 组数,每组数由 5 个整数构成,这 5 个整数依次为线段 l_ili 的两个端点 P_i, Q_iPi,Qi 的坐标(有序数对)x_{P_i}, y_{P_i}, x_{Q_i}, y_{Q_i}xPi,yPi,xQi,yQi 和优美度 v_ivi.
输出
输出一个整数,代表最大的优美度之和。
输入样例
2 0 0 2 2 1 0 2 2 0 2
输出样例
6
复制样例
题解
每条线段的固定收益可以直接求和.
然后可以有一万种方法求出线段的交.把线段看作点,交看作边,得到一张有向图.
观察到由高点权到低点权且有交的限制构成了一张DAG, 考虑如何最大化被选择的路径上的边权和.把每个点
拆成和, 若原图上存在边, 则连边, 权值为收益, 这样就可以合并以为终点, 以为起点的路
径, 并获得边权的额外收益.
由于二分图匹配的特性, 原图上每个点只能进入一次, 离开一次, 符合题目要求, 跑一个二分图最大权匹配就可
以了.
需要注意的是, 如果使用了最大费用最大流(EK)算法, 需要在增广出负的费用时退出, 因为在本题中我们要最大
化权值, 而不是最大化流量."
#include <bits/stdc++.h>
using namespace std;
typedef double db;
typedef long double ldb;
typedef long long ll;
const int maxn = 2005;
const ldb eps = 1e-9;
const int inf = 0x3f3f3f3f;
char line[1000001];
struct Vector
{
ldb x, y;
Vector(ldb xx = 0, ldb yy = 0):x(xx),y(yy){}
Vector operator + (Vector rhs)
{
return Vector(x + rhs.x, y + rhs.y);
}
Vector operator - (Vector rhs)
{
return Vector(x - rhs.x, y - rhs.y);
}
ldb operator * (Vector rhs)
{
return x * rhs.x + y * rhs.y;
}
friend Vector operator * (Vector lhs, ldb rhs)
{
return Vector(lhs.x * rhs, lhs.y * rhs);
}
ldb operator ^ (Vector rhs)
{
return x * rhs.y - y * rhs.x;
}
bool operator < (const Vector &rhs) const
{
return (x == rhs.x) ? (y < rhs.y) : x < rhs.x;
}
};
ldb norm(Vector a)
{
return sqrt(a * a);
}
typedef Vector Point;
struct Line
{
Point P;
Point V;
Line(Point P_ = Point(), Point V_ = Point()):P(P_), V(V_)
{}
}l[maxn];
inline int DCMP(ldb x)
{
if(x > -eps && x < eps) return 0;
else return (x > 0) ? 1 : -1;
}
Point intersection(Line a, Line b)
{
if(!DCMP(a.V ^ b.V)) return Point(-inf, -inf);
return b.P + b.V*((a.V ^ (a.P - b.P))/(a.V ^ b.V));
}
ldb dist(Point p, Point q)
{
return norm(p - q);
}
inline bool legal(Line a, Line b)
{
Point p = intersection(a, b);
//printf("%Lf %Lf\n", p.x, p.y);
ldb mnax = min(a.P.x, a.P.x + a.V.x), mxax = max(a.P.x, a.P.x + a.V.x);
ldb mnay = min(a.P.y, a.P.y + a.V.y), mxay = max(a.P.y, a.P.y + a.V.y);
ldb mnbx = min(b.P.x, b.P.x + b.V.x), mxbx = max(b.P.x, b.P.x + b.V.x);
ldb mnby = min(b.P.y, b.P.y + b.V.y), mxby = max(b.P.y, b.P.y + b.V.y);
if(DCMP(p.x - mnax) >= 0 && DCMP(p.x - mxax) <= 0
&& DCMP(p.y - mnay) >= 0 && DCMP(p.y - mxay) <= 0
&& DCMP(p.x - mnbx) >= 0 && DCMP(p.x - mxbx) <= 0
&& DCMP(p.y - mnby) >= 0 && DCMP(p.y - mxby) <= 0)
return true;
else return false;
}
//computational geometry over
struct edge
{
int to, nxt, w, c;
}e[maxn * maxn << 1];
int n, s, t, ptr, lnk[maxn], dis[maxn], pre[maxn], id[maxn];
int val[maxn], vis[maxn];
inline void add(int bgn, int end, int val, int cost)
{
e[ptr].to = end; e[ptr].nxt = lnk[bgn]; e[ptr].w = val; e[ptr].c = cost; lnk[bgn] =
ptr; ++ptr;
e[ptr].to = bgn; e[ptr].nxt = lnk[end]; e[ptr].w = 0; e[ptr].c = -cost; lnk[end] =
ptr; ++ptr;
}
inline bool spfa()
{
//memset(dis, 0x3f, sizeof dis);
for(int i = s; i <= t; ++i) dis[i] = -0x3f3f3f3f;
dis[s] = 0; queue<int> q; q.push(s); vis[s] = 1;
while(!q.empty())
{
int u = q.front(); q.pop(); vis[u] = 0;
for(int p = lnk[u]; ~p; p = e[p].nxt)
{
int y = e[p].to;
if(e[p].w && dis[y] < dis[u] + e[p].c)
{
dis[y] = dis[u] + e[p].c;
pre[y] = u;
id[y] = p;
if(!vis[y]) vis[y] = 1, q.push(y);
}
}
}
return dis[t] > -0x3f3f3f3f;
}
inline int costflow()
{
int flow = 0, cost = 0, aug;
while(spfa())
{
if(dis[t] < 0) break;
aug = 0x3f3f3f3f;
for(int p = t; p != s; p = pre[p])
aug = min(aug, e[id[p]].w);
//if(aug < 0) break;
flow += aug; cost += aug * dis[t];
for(int p = t; p != s; p = pre[p])
e[id[p]].w -= aug, e[id[p]^1].w += aug;
}
return cost;
}
int main()
{
//freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
while (scanf("%d", &n) != EOF) {
ptr = 0;
memset(lnk, -1, sizeof lnk);int sum = 0;
s = 0; t = n * 2 + 1;
for(int i = 1; i <= n; ++i)
{
int px, py, qx, qy;
scanf("%d%d%d%d%d", &px, &py, &qx, &qy, &val[i]);
sum += val[i];
l[i] = Line(Point(px, py), Point(qx - px, qy - py));
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
{
if(i == j || val[i] <= val[j]) continue;
if(legal(l[i], l[j]))
//cout << i << " to " << j << endl,
add(i, j + n, 1, (val[i] + val[j]) * ((i + j) / 2));
}
for(int i = 1; i <= n; ++i) add(s, i, 1, 0), add(i + n, t, 1, 0);
printf("%d\n", costflow() + sum);
}
return 0;
}