kuangbin题单|数学训练一

数学训练(×)

脑筋急转弯()

1.LightOJ1008 Fibsieve's Fantabulous Birthday 找规律

此题已经写过题解了,看@此处

2.LightOJ1010 Knights in Chessboard 找规律

没想出来,分享好题解@此处

总结就是讨论min(n,m)的取值,如果大于2,直接取棋盘的黑色部分。

如果等于2,将棋盘划分为若干个22的田,剩下的部分长度只能为3,2,13的情况就是一个田加上一个空白区域,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个棋子,每人每次可以拿1m个:

  1. 如果取最后子判胜,那么当n%(m+1)==0时后手必胜,否则先手必胜。

简单证明:

无论先手取多少子,后手都可以取一定的量使两者和为(m+1)(比如先手取m个,后手则可以取1个)。这使得取子变为nm+1轮和最后一轮。若最后一轮不存在,显然是后手取最后一子,故后手必胜。

  1. 如果取最后子判负,那么当(n1)%(m+1)==0时后手必胜,否则先手必胜。

简单证明:

取最后子判负,等价于先取完前n1个子的获胜,也就是判断谁先取到第n1个子,此时与第一种情况相同。

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 模拟

digitk,模数为n,答案为y

y的初始值为k,显然迭代过程是y%n=(y10+k)%n=[(y10)%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可以表示成2w/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被分为了cnt[i]i+1组,如果cnt[i]能被i+1整除,ans+=cnt[i]i+1(i+1),否则ans+=cnt[i]i+1(i+1)+(i+1),即前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 约瑟夫环

套个递推公式就出来了,看着231怪大的其实压根没爆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 小学数学

易推得,每两组的和为m2,一共有n2m组,所以答案是n2mm2=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(l2x)(w2x)

一阶导可得:V(x)=12x24(l+w)x+wl

易知V(x)无整数解,令L=0,R=w/2,eps=1e6进行二分,答案带入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);
}
posted @   SxtoxA  阅读(24)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
12 13
点击右上角即可分享
微信分享提示