kuangbin题单|数学训练一
数学训练(×)
脑筋急转弯\((\checkmark)\)
1.LightOJ1008 Fibsieve's Fantabulous Birthday 找规律
此题已经写过题解了,看@此处
2.LightOJ1010 Knights in Chessboard 找规律
没想出来,分享好题解@此处
总结就是讨论\(min(n,m)\)的取值,如果大于\(2\),直接取棋盘的黑色部分。
如果等于\(2\),将棋盘划分为若干个\(2*2\)的田,剩下的部分长度只能为\(3,2,1\)。\(3\)的情况就是一个田加上一个空白区域,\(2\)的情况就是一个田,\(1\)的情况就是一个长条。
如果等于\(1\),显然每一块都可以放一个骑士,答案为\(m\)。
void solve(int kase) {
cin >> m >> n;
if (n > m) swap(n, m);
if (n > 2) {
printf("Case %d: %d\n", kase, (n * m + 1) / 2);
return;
} else if (n == 2) {
int t = 0;
if (m % 4 == 3 || m % 4 == 2) t = 2;
else if (m % 4 == 1) t = 1;
else t = 0;
printf("Case %d: %d\n", kase, 4 * (m / 4) + 2 * t);
return;
} else printf("Case %d: %d\n", kase, m);
}
3.LightOJ1020 A Childhood Game 巴什博弈
本题是\(m=2\)情况下的巴什博弈。
对于\(n\)个棋子,每人每次可以拿\(1\sim m\)个:
- 如果取最后子判胜,那么当\(n\%(m+1)==0\)时后手必胜,否则先手必胜。
简单证明:
无论先手取多少子,后手都可以取一定的量使两者和为\((m+1)\)(比如先手取\(m\)个,后手则可以取\(1\)个)。这使得取子变为\(\frac{n}{m+1}\)轮和最后一轮。若最后一轮不存在,显然是后手取最后一子,故后手必胜。
- 如果取最后子判负,那么当\((n-1)\%(m+1)==0\)时后手必胜,否则先手必胜。
简单证明:
取最后子判负,等价于先取完前\(n-1\)个子的获胜,也就是判断谁先取到第\(n-1\)个子,此时与第一种情况相同。
void solve(int kase) {
string win = "";
int m = 2;
if (s == "Bob") {
if (n % (m + 1) == 0) win = "Alice";
else win = "Bob";
} else {
if ((n - 1) % (m + 1) == 0) win = "Bob";
else win = "Alice";
}
printf("Case %d: %s\n", kase, win.c_str());
}
4.LightOJ1078 Integer Divisibility 模拟
设\(digit\)为\(k\),模数为\(n\),答案为\(y\)。
\(y\)的初始值为\(k\),显然迭代过程是\(y\%n=(y*10+k)\%n=[(y*10)\%n+k\%n]\%n\)。
循环直到\(y\%n==0\)为止。
void solve(int kase) {
LL y = k;
int ans = 1;
while (y % n != 0) {
y = (y * 10) % n + k % n;
ans++;
}
printf("Case %d: %d\n", kase, ans);
}
5.LightOJ1116 Ekka Dokka 质因数分解
显然若\(w\)是奇数,一定无法分解成奇数*偶数。
继续讨论,如果\(w\)可以表示成\(2*w/2\),其中\(w/2\)是奇数,那么一定是满足最小偶数的条件的。
否则,我们对\(w\)的所有质因数进行分析。要求最小偶数等价于最大奇数,最大的奇数=所有不包括\(2\)的质因数之积,在实际代码中,只要不断\(w/2\)直到\(w\)为奇数即可。
void solve(int kase) {
if (n & 1LL) {
printf("Case %d: Impossible\n", kase);
return;
}
if (((n >> 1LL) & 1LL)) {
printf("Case %d: %lld %lld\n", kase, n / 2, 2);
return;
} else {
LL t = n;
while (t) {
if (t & 1LL) break;
t >>= 1LL;
}
printf("Case %d: %lld %lld\n", kase, t, n / t);
}
}
6.LightOJ1148 Mad Counting 找规律
设\(cnt[i]\)为\(i\)出现的次数。我们举一个例子:1 1 1 1 1
可以发现,满足最小人数的分组是\([1\ 1\ 1],[1\ 1]\),
也就是说:对于同一个\(i\)被分为了\(\frac{cnt[i]}{i+1}\)组,如果\(cnt[i]\)能被\(i+1\)整除,\(ans+=\frac{cnt[i]}{i+1}*(i+1)\),否则\(ans+=\frac{cnt[i]}{i+1}*(i+1)+(i+1)\),即前\(\frac{cnt[i]}{i+1}\)组的人数+最后一组的人数。
void solve(int kase) {
memset(cnt, 0, sizeof(cnt));
cin >> n;
int L = inf, R = -1;
int ans = 0;
while (n--) {
int x;
cin >> x;
cnt[x]++;
L = min(L, x);
R = max(R, x);
}
for (int i = L; i <= R; i++) {
if (cnt[i] % (i + 1) != 0) ans += (cnt[i] / (i + 1)) * (i + 1) + (i + 1);
else ans += cnt[i];
}
printf("Case %d: %d\n", kase, ans);
}
7.LightOJ1179 Josephus Problem 约瑟夫环
套个递推公式就出来了,看着\(2^{31}\)怪大的其实压根没爆\(int\)
void solve(int kase) {
cin >> n >> k;
int ans = 0;
for (int i = 1; i <= n; i++) ans = (ans + k) % i;
printf("Case %d: %d\n", kase, ans + 1);
}
8.LightOJ1275 Internet Service Providers 小学数学
呃,一元二次方程。
int count(int x) {
return -n * x * x + c * x;
}
void solve(int kase) {
cin >> n >> c;
int ans = 0;
if (!n || !c) {
printf("Case %d: 0\n", kase);
return;
}
if (!c % (2 * n)) {
ans = c / (2 * n);
} else {
int temp = c / (2 * n);
if (count(temp) < count(temp + 1)) ans = temp + 1;
else ans = temp;
}
printf("Case %d: %d\n", kase, ans);
}
9.LightOJ1294 Positive Negative Sign 小学数学
易推得,每两组的和为\(m^2\),一共有\(\frac{n}{2m}\)组,所以答案是\(\frac{n}{2m}*m^2=mn/2\)
void solve(int kase) {
cin >> n >> m;
LL ans = n * m >> 1LL;
printf("Case %d: %lld\n", kase, ans);
}
10.LightOJ1297 Largest Box 带精度二分
体积\(V(x)=x(l-2x)(w-2x)\)
一阶导可得:\(V'(x)=12x^2-4(l+w)x+wl\)。
易知\(V'(x)\)无整数解,令\(L=0,R=w/2,eps=1e-6\)进行二分,答案带入\(V(x)\)即可。
double calc(double x) {
return (double) (x * (w - 2 * x) * (l - 2 * x));
}
double calc2(double x) {
return (double) (12 * x * x - 4 * (l + w) * x + w * l);
}
double solve2() {
double l = 0, r = w / 2.0;
double ans = 0;
while (r - l > eps) {
double mid = (l + r) / 2.0;
if (calc2(mid) > 0) l = mid, ans = l;//图像可知导函数严格递减
else r = mid - eps;
}
return ans;
}
void solve(int kase) {
cin >> l >> w;
if (w > l) swap(l, w);
double x1 = solve2();
double ans = calc(x1);
printf("Case %d: %lf\n", kase, ans);
}

浙公网安备 33010602011771号