A - Sqrt Bo(HDU 5752)
大意
定义
f(x)
的值为
x
开方后向下取整的结果。题给一个整数
思路
当
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll upperBound = 4294836224LL;
ll a;
string s;
stringstream ss;
int main() {
while(cin >> s) {
if(s.size() > 10) {
puts("TAT");
continue;
}
ss.clear();
ss << s;
ss >> a;
if(a < 1 || a > upperBound) {
puts("TAT");
continue;
}
bool ok = false;
for(int i = 0; i <= 5; i++) {
if(a == 1) {
cout << i << endl;
ok = true;
break;
}
a = (ll)floor(sqrt(1.0 * a));
}
if(ok == false) {
puts("TAT");
}
}
return 0;
}
B - Permutation Bo(HDU 5753)
大意
题给一个序列
思路
根据本题的数据规模来看,肯定无法枚举排列然后算期望了。一个可行的思维是算出序列 c 中每个元素对期望的贡献。
- 当考虑
c 的第 1 个元素c1 时,我们只要考虑前两个元素的排列,当前两个元素呈现出 c1>c2 时 c1 的贡献就会被算进期望中。显然 c1>c2 的概率是 12 。- 当考虑
c
的第
2 个元素 c2 时,我们只要考虑前三个元素的排列,当前三个排列呈现出 c1<c2,c3<c2 时, c2 的贡献就回被算进期望中。显然这种排列的概率是 13 。 - 第
3
到第
n−1 个元素的贡献与第 2 个元素的贡献相似。第n 个元素的贡献与第 1 个元素的贡献相似。
于是我们枚举每个元素,将其贡献加入期望中即可。
代码
#include <bits/stdc++.h> using namespace std; int n, a; double ans; int main() { while(~scanf("%d", &n)) { ans = 0; for(int i = 1; i <= n; i++) { scanf("%d", &a); if(i == 1 || i == n) { ans += 1.0 * a / 2; } else { ans += 1.0 * a / 3; } } if(n == 1) { printf("%.5f\n", 1.0 * a); } else { printf("%.5f\n", ans); } } return 0; }
C - Life Winner Bo(HDU 5754)
大意
有两个人在国际象棋棋盘上用国际象棋一个棋子进行博弈,这个棋子可能是王,王后,城堡和骑士。棋子从坐标
(1,1) 出发,两个人轮流让棋子按照国际象棋规则走一次,先让棋子到达 (N,M) 的人获胜。问先手和后手谁是赢家。思路
根据国际象棋棋盘的特点,该游戏可以抽象成从两个石子堆(分别有 N−1,M−1 个石子)中拿石子,先将所有石子拿完的人获胜的博弈模型。根据四个棋子的走法不同,抽象模型中拿石子的方法也会有所不同。下面就分棋子进行讨论。
- 王:由于王可以在一次移动中横向,纵向或斜向移动一步,因此对应到拿石子模型中,当两堆石子的数量 N−1,M−1 都是偶数的时候当前状态是必败态(否则一定可以通过一次行动使得当前两堆石子的数量变成偶数)。
- 城堡:由于城堡可以在一次移动中横向或者纵向移动任意步,因此对应到拿石子的模型中,与 NimGame 模型是一样的。因此只有 N=M 的时候先手失败,其余情况下是先手获胜(先手总可以令对方面对两堆石子数目相同的情况,这种情况是必败态)。
- 骑士:由于骑士可以在一次移动中横移两步纵移一步或横移一步纵移两步,因此对应到拿石子模型中,相当于在
N−1,M−1
两堆石子中一堆拿一个,而另一堆拿两个。当
N−1+M−1
不是
3
的倍数的时候一定是平局。当它是
3 的倍数的时候,当 N=M 时一定是必败的,因为只要想脱离必败态(例如两堆石子分别 −1,−2 )就一定会被赶回必败态(例如两堆石子分别 −2,−1 )。若 N,M 不等且它们的差值为 1 时一定是必胜的,因为必定可以用一步把对手逼入必败态。 - 王后:由于王后可以在一次移动中横向,纵向或斜向移动任意步,因此对应到拿石子的模型中,与
WythoffGame 模型是一样的。因此可以用公式 ai=⌊i×(1+5√)/2⌋,bi=ai+i 检验当前局势 (N−1,M−1) 是否是必败局势。
代码
#include <bits/stdc++.h> using namespace std; const int maxn = 1000; char ch[] = {'G', 'D', 'B'}; int t, type, n, m, ans, G[maxn+5][maxn+5]; int king() { return n % 2 == 1 && m % 2 == 1 ? -1 : 1; } int castle() { return n == m ? -1 : 1; } int knight() { if(n > m) { swap(n, m); } if(n == m && (n - 4) % 3 == 0 && n >= 4) { return -1; } if(n % 3 == 2 && m % 3 == 0 && m - n == 1) { return 1; } return 0; } int queen() { if(n > m) { swap(n, m); } int a = n - 1, b = m - 1, k = m - n; double tmp = (1.0 + sqrt((double)5.0)) / 2.0; return (int)(k * tmp) == a ? -1 : 1; } int main() { scanf("%d", &t); while(t--) { scanf("%d%d%d", &type, &n, &m); if(type == 1) { ans = king(); } if(type == 2) { ans = castle(); } if(type == 3) { ans = knight(); } if(type == 4) { ans = queen(); } printf("%c\n", ch[ans+1]); } return 0; }
J - Rower Bo(HDU 5761)
大意
主人公要驾船从平面直角坐标系中的 (0,a) 去到 (0,0) 。主人公的船相对水流的速度大小恒为 v1 ,方向始终朝向 (0,0) 。河流有一个垂直于 y 轴的速度
v2 。问主人公从出发到目的地要花多少时间。思路
再思考无果的时候,不妨将问题转化一下:主人公从 (0,a) 出发,目的地以 v2 的速度向x轴正向移动,而水流是静止的。主人公始终以 v1 的速度朝向目的地移动,问主人公到达目的地的时间。
设T为主人公要花的时间,另外主人公在 t 时刻的速度与x 轴方向的夹角为 θ(t) 。我们考虑主人公在水平和竖直方向上方向上的运动情况,对水平方向有∫T0v1cosθ(t)dt=v2T
对竖直方向有
∫T0v1sinθ(t)dt=a
此时还有一个条件没有利用,那就是主人公的速度方向始终朝向终点,那么对主人公当前位置到目的地的方向有
∫T0(v1−v2cosθ(t))dt=a
最后联立这三个方程可得
T=v1av21+v22
于是原问题得解。
代码
#include <bits/stdc++.h> using namespace std; int a, v1, v2; int main() { while(~scanf("%d%d%d", &a, &v1, &v2)) { if(a == 0) { puts("0.00000"); } else if(v1 <= v2) { puts("Infinity"); } else { printf("%.5f\n", 1.0 * v1 * a / (v1 * v1 - v2 * v2)); } } return 0; }
K - Teacher Bo(HDU 5762)
大意
题给 n 个点
(x,y) ,并约定 0≤x,y≤m 。问是否能从这些点钟找出一个四元组 (A,B,C,D) ,使得二元组 (A,B) 与二元组 (C,D) 的曼哈顿距离相等。(这两个二元组不能相同)思路
虽然看上去不同的二元组会很多,但是根据鸽巢原理,当 n(n−1)2(不同的二元组数)>2√m(不同的曼哈顿距离数时) ,所求的四元组是一定能够被找到的,因此即使我们暴力枚举所有的二元组,复杂度也将是 min(n(n−1)2,2√m) 。为了立即发现重复,我们需要一个数组 vis , vis[x]=true 表示曼哈顿距离为x的二元组已经出现过了。在 m <script id="MathJax-Element-46" type="math/tex">m</script> 不是很大的情况下,维护这样一个数组的空间也不会超出限制。
代码
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; bool ok; int t, n, m, dx, dy, mht, x[maxn], y[maxn], vis[maxn]; int main() { scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%d%d", &x[i], &y[i]); } memset(vis, 0, sizeof(vis)); ok = false; for(int i = 1; i <= n; i++) { for(int j = i + 1; j <= n; j++) { dx = abs(x[i] - x[j]); dy = abs(y[i] - y[j]); mht = dx + dy; if(vis[mht] == true) { ok = true; i = n + 1; break; } vis[mht] = true; } } puts(ok ? "YES" : "NO"); } return 0; }
(其它题目略)
- 当考虑
c
的第