<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>特定倍数的约数个数 - 完整教学</title>
<style>
* {
box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
}
html, body {
margin: 0;
padding: 0;
background: #F0F4F8;
overflow: hidden;
height: 100vh;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
-webkit-text-size-adjust: 100%;
}
#app {
height: 100vh;
width: 100%;
max-width: 480px;
margin: 0 auto;
background: #fff;
display: flex;
flex-direction: column;
box-shadow: 0 0 20px rgba(0,0,0,0.05);
}
.content-area {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding-bottom: 80px;
-webkit-overflow-scrolling: touch;
}
.top-tabs {
display: flex;
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
padding: 10px 10px 0 10px;
gap: 5px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.top-tab {
flex-shrink: 0;
padding: 10px 12px;
border-radius: 12px 12px 0 0;
font-size: 12px;
font-weight: bold;
color: rgba(255,255,255,0.7);
cursor: pointer;
transition: all 0.3s;
background: rgba(255,255,255,0.1);
min-width: 90px;
text-align: center;
}
.top-tab.active {
background: white;
color: #059669;
transform: translateY(-2px);
box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
}
.bottom-nav {
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 100%;
max-width: 480px;
height: 70px;
background: white;
border-top: 1px solid #e0e0e0;
display: flex;
justify-content: space-around;
align-items: center;
z-index: 1000;
box-shadow: 0 -2px 10px rgba(0,0,0,0.05);
}
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
padding: 8px;
transition: all 0.3s;
color: #64748B;
}
.nav-item.active { color: #10B981; }
.nav-icon { font-size: 24px; margin-bottom: 4px; }
.nav-label { font-size: 12px; font-weight: 500; }
.page-container { padding: 20px; }
.section-title {
font-size: 20px;
font-weight: 800;
color: #1E293B;
margin: 20px 0 15px 0;
display: flex;
align-items: center;
gap: 8px;
}
.card {
background: white;
border-radius: 12px;
padding: 20px;
margin-bottom: 15px;
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
border: 1px solid #E2E8F0;
}
.tag {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
margin-bottom: 8px;
}
.tag-blue { background: #E0F2FE; color: #0284C7; }
.tag-green { background: #D1FAE5; color: #065F46; }
.tag-orange { background: #FFEDD5; color: #C2410C; }
.tag-purple { background: #F3E8FF; color: #7C3AED; }
.tag-emerald { background: #D1FAE5; color: #059669; }
.formula-box {
background: linear-gradient(135deg, #D1FAE5 0%, #A7F3D0 100%);
padding: 20px;
border-radius: 12px;
border: 3px solid #10B981;
margin: 15px 0;
text-align: center;
}
.formula-title {
font-size: 14px;
font-weight: bold;
color: #059669;
margin-bottom: 10px;
}
.formula-content {
font-size: 18px;
font-weight: bold;
color: #1E293B;
}
.speak-btn {
background: linear-gradient(135deg, #10B981 0%, #059669 100%);
color: white;
border: none;
padding: 12px 20px;
border-radius: 20px;
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
box-shadow: 0 4px 10px rgba(16, 185, 129, 0.3);
width: 100%;
}
.anim-stage {
background: #1E293B;
border-radius: 16px;
padding: 25px 15px;
min-height: 400px;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
border: 2px solid #334155;
margin: 15px 0;
}
.anim-text {
color: white;
margin-top: auto;
font-size: 14px;
font-weight: bold;
text-align: center;
min-height: 60px;
background: rgba(0,0,0,0.4);
padding: 12px 15px;
border-radius: 20px;
backdrop-filter: blur(4px);
width: 100%;
display: flex;
align-items: center;
justify-content: center;
line-height: 1.5;
}
.step-controls {
display: flex;
gap: 10px;
margin-bottom: 15px;
justify-content: center;
flex-wrap: wrap;
}
.step-btn {
background: #10B981;
color: white;
border: none;
padding: 8px 20px;
border-radius: 20px;
font-weight: bold;
font-size: 13px;
cursor: pointer;
transition: all 0.2s;
}
.step-btn:disabled { background: #CBD5E1; cursor: not-allowed; }
.step-btn:active:not(:disabled) { transform: scale(0.95); }
.calc-demo {
color: white;
width: 100%;
margin-top: 20px;
}
.calc-step {
background: rgba(255,255,255,0.1);
padding: 15px;
border-radius: 10px;
margin-bottom: 15px;
opacity: 0;
border: 2px solid transparent;
}
.calc-step.active {
border-color: #10B981;
background: rgba(16, 185, 129, 0.2);
}
.calc-equation {
font-size: 16px;
text-align: center;
margin-bottom: 8px;
}
.calc-highlight {
color: #FCD34D;
font-size: 20px;
font-weight: bold;
}
.calc-explanation {
font-size: 12px;
color: #CBD5E1;
text-align: center;
margin-top: 5px;
}
.visual-demo {
width: 100%;
margin-top: 20px;
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
}
.divisor-grid {
display: flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
max-width: 100%;
}
.divisor-box {
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
font-size: 16px;
font-weight: bold;
color: white;
background: #3B82F6;
}
.divisor-multiple {
background: #10B981;
border: 3px solid #FCD34D;
}
.divisor-normal {
background: #64748B;
}
.question-card {
background: white;
border-radius: 16px;
padding: 20px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
margin-bottom: 15px;
}
.question-text {
font-size: 16px;
font-weight: bold;
margin-bottom: 15px;
line-height: 1.6;
color: #1E293B;
}
.answer-input {
width: 100%;
padding: 12px;
border: 2px solid #E2E8F0;
border-radius: 8px;
font-size: 16px;
margin-bottom: 10px;
}
.submit-btn {
background: #10B981;
color: white;
border: none;
padding: 12px;
border-radius: 8px;
width: 100%;
font-weight: bold;
font-size: 16px;
cursor: pointer;
}
.feedback-box {
margin-top: 10px;
padding: 12px;
border-radius: 8px;
font-size: 13px;
line-height: 1.6;
}
.feedback-correct {
background: #ECFDF5;
color: #047857;
border: 2px solid #10B981;
}
.feedback-wrong {
background: #FEF2F2;
color: #B91C1C;
border: 2px solid #EF4444;
}
.concept-card {
background: linear-gradient(135deg, #DBEAFE 0%, #BFDBFE 100%);
border: 2px solid #3B82F6;
border-radius: 12px;
padding: 15px;
margin: 15px 0;
}
.concept-title {
font-size: 15px;
font-weight: bold;
color: #1E40AF;
margin-bottom: 10px;
}
.arrow-box {
display: flex;
align-items: center;
gap: 10px;
justify-content: center;
margin: 15px 0;
}
.arrow {
color: #FCD34D;
font-size: 24px;
font-weight: bold;
}
.math-box {
background: rgba(255,255,255,0.15);
padding: 12px 20px;
border-radius: 10px;
color: white;
font-size: 16px;
font-weight: bold;
border: 2px solid #10B981;
}
</style>
</head>
<body>
<div id="app">
<div class="content-area">
<!-- Page 1: 核心原理 -->
<div v-show="currentPage === 1">
<div class="top-tabs">
<div class="top-tab" :class="{active: theoryTab === 'review'}" @click="theoryTab = 'review'">
知识回顾
</div>
<div class="top-tab" :class="{active: theoryTab === 'core'}" @click="theoryTab = 'core'">
核心思想
</div>
<div class="top-tab" :class="{active: theoryTab === 'example'}" @click="theoryTab = 'example'">
举例详解
</div>
<div class="top-tab" :class="{active: theoryTab === 'advanced'}" @click="theoryTab = 'advanced'">
进阶视角
</div>
</div>
<div class="page-container">
<!-- 知识回顾 -->
<div v-show="theoryTab === 'review'">
<div class="section-title">📚 知识回顾:约数个数公式</div>
<div class="card">
<div class="tag tag-blue">质因数分解</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
对一个正整数 $N$ 进行质因数分解:
</p>
<div style="background: #EFF6FF; padding: 15px; border-radius: 8px; margin: 10px 0; text-align: center;">
$N = p_1^{a_1} \cdot p_2^{a_2} \cdots p_n^{a_n}$
</div>
<p style="font-size: 13px; color: #64748B;">
其中 $p_i$ 是不同的质数,$a_i$ 是它们的指数
</p>
</div>
<div class="formula-box">
<div class="formula-title">★ 约数个数公式 ★</div>
<div class="formula-content">
$\tau(N) = (a_1+1)(a_2+1)\cdots(a_n+1)$
</div>
</div>
<div class="card">
<div class="tag tag-emerald">经典例子:72</div>
<div class="step-controls">
<button class="step-btn" @click="animateReview">▶️ 演示计算过程</button>
</div>
<div class="anim-stage">
<div class="calc-demo" id="review-demo"></div>
<div class="anim-text" id="review-text">点击按钮开始演示</div>
</div>
</div>
<button class="speak-btn" @click="speakReview">
🔊 听讲解
</button>
</div>
<!-- 核心思想 -->
<div v-show="theoryTab === 'core'">
<div class="section-title">💡 核心思想:把 k 提出来</div>
<div class="concept-card">
<div class="concept-title">研究目标</div>
<div style="font-size: 14px; color: #1E40AF; line-height: 1.8;">
求 $N$ 的约数中,有多少个是 $k$ 的倍数?<br>
记作:$\tau_{k\text{-倍数}}(N)$
</div>
</div>
<div class="card">
<div class="tag tag-orange">前提条件</div>
<div style="background: #FEF3C7; padding: 15px; border-radius: 8px; margin: 10px 0;">
如果 $k$ 不是 $N$ 的约数($k \nmid N$),<br>
那么答案直接是 <strong style="color: #DC2626;">0</strong>
</div>
</div>
<div class="card">
<div class="tag tag-blue">推导过程</div>
<div class="step-controls">
<button class="step-btn" @click="animateCore">▶️ 演示推导过程</button>
</div>
<div class="anim-stage">
<div class="calc-demo" id="core-demo"></div>
<div class="anim-text" id="core-text">点击按钮开始演示</div>
</div>
</div>
<div class="formula-box">
<div class="formula-title">★ 核心公式 ★</div>
<div class="formula-content">
$\tau_{k\text{-倍数}}(N) = \tau\left(\frac{N}{k}\right)$
</div>
</div>
<button class="speak-btn" @click="speakCore">
🔊 听讲解
</button>
</div>
<!-- 举例详解 -->
<div v-show="theoryTab === 'example'">
<div class="section-title">📝 举例详解:72的12倍数约数</div>
<div class="card">
<div class="tag tag-emerald">题目</div>
<p style="font-size: 15px; font-weight: bold; color: #334155; margin: 10px 0;">
$N = 72 = 2^3 \times 3^2$<br>
求72的约数中,有多少是12的倍数?
</p>
</div>
<div class="card">
<div class="tag tag-purple">详细步骤(动画演示)</div>
<div class="step-controls">
<button class="step-btn" @click="animateExample">▶️ 演示解题过程</button>
</div>
<div class="anim-stage">
<div class="calc-demo" id="example-demo"></div>
<div class="anim-text" id="example-text">点击按钮开始演示</div>
</div>
</div>
<div class="card">
<div class="tag tag-green">验证答案</div>
<div class="step-controls">
<button class="step-btn" @click="animateVerify">▶️ 显示所有约数</button>
</div>
<div class="anim-stage">
<div class="visual-demo" id="verify-demo"></div>
<div class="anim-text" id="verify-text">点击按钮开始验证</div>
</div>
</div>
<button class="speak-btn" @click="speakExample">
🔊 听讲解
</button>
</div>
<!-- 进阶视角 -->
<div v-show="theoryTab === 'advanced'">
<div class="section-title">🚀 进阶视角:质因数分解直接法</div>
<div class="card">
<div class="tag tag-blue">问题重述</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin: 10px 0;">
$N = 72 = 2^3 \times 3^2$<br>
$k = 12 = 2^2 \times 3^1$<br><br>
求 $N$ 的约数中,有多少是 $k$ 的倍数?
</p>
</div>
<div class="card">
<div class="tag tag-purple">直接法思路</div>
<div class="step-controls">
<button class="step-btn" @click="animateAdvanced">▶️ 演示直接法</button>
</div>
<div class="anim-stage">
<div class="calc-demo" id="advanced-demo"></div>
<div class="anim-text" id="advanced-text">点击按钮开始演示</div>
</div>
</div>
<div class="card">
<div class="tag tag-green">方法对比</div>
<div style="background: #ECFDF5; padding: 15px; border-radius: 8px; margin: 10px 0; font-size: 13px; line-height: 1.8;">
<strong>方法一(公式法):</strong><br>
$\tau(N/k) = \tau(2^1 \times 3^1) = 2 \times 2 = 4$<br><br>
<strong>方法二(直接法):</strong><br>
2的指数范围:2~3 (2种)<br>
3的指数范围:1~2 (2种)<br>
总数:$2 \times 2 = 4$<br><br>
<strong style="color: #059669;">两种方法结果一致!✓</strong>
</div>
</div>
<button class="speak-btn" @click="speakAdvanced">
🔊 听讲解
</button>
</div>
</div>
</div>
<!-- Page 2: 5道经典例题 -->
<div v-show="currentPage === 2">
<div class="top-tabs">
<div class="top-tab" :class="{active: exampleIndex === index}"
v-for="(ex, index) in classicExamples" :key="'tab-' + index"
@click="switchExample(index)">
例题{{ index + 1 }}
</div>
</div>
<div class="page-container">
<div v-for="(ex, index) in classicExamples" :key="'example-' + index"
v-show="exampleIndex === index">
<div class="section-title">{{ ex.title }}</div>
<div class="card">
<div class="tag tag-blue">题目</div>
<div class="question-text" v-html="ex.question"></div>
</div>
<div class="card">
<div class="tag tag-emerald">分步解析(动画演示)</div>
<div class="step-controls">
<button class="step-btn" @click="prevExampleStep(index)" :disabled="exampleSteps[index] === 0">
◀ 上一步
</button>
<button class="step-btn" @click="nextExampleStep(index)" :disabled="exampleSteps[index] >= ex.steps.length - 1">
下一步 ▶
</button>
<button class="step-btn" @click="resetExampleStep(index)" style="background: #64748B;">
🔄 重置
</button>
<button class="step-btn" @click="speakExampleVoice(index)" style="background: #F59E0B;">
🔊 语音
</button>
</div>
<div class="anim-stage">
<div class="calc-demo">
<div v-for="(step, sIndex) in ex.steps" :key="'step-' + sIndex"
class="calc-step"
:class="{active: exampleSteps[index] === sIndex}"
:style="{opacity: exampleSteps[index] >= sIndex ? 1 : 0}">
<div class="calc-equation" v-html="step.equation"></div>
<div class="calc-explanation">{{ step.explanation }}</div>
</div>
</div>
<div class="anim-text">
{{ exampleSteps[index] < ex.steps.length ? ex.steps[exampleSteps[index]].text : '已完成所有步骤' }}
</div>
</div>
</div>
<div class="card">
<div class="tag tag-green">答案</div>
<div style="background: #ECFDF5; padding: 15px; border-radius: 8px; border-left: 3px solid #10B981;" v-html="ex.answer"></div>
</div>
</div>
</div>
</div>
<!-- Page 3: 10道练习题 -->
<div v-show="currentPage === 3" class="page-container">
<div class="section-title">✏️ 10道课程练习</div>
<div v-if="!practiceDone">
<div class="question-card">
<div class="tag tag-blue">练习 {{ currentPracticeIndex + 1 }}/10</div>
<div class="question-text" v-html="practiceQuestions[currentPracticeIndex].question"></div>
<input
type="text"
class="answer-input"
v-model="userAnswer"
placeholder="输入答案"
@keyup.enter="checkPracticeAnswer"
:disabled="practiceAnswered">
<button class="submit-btn" @click="checkPracticeAnswer" v-if="!practiceAnswered">
提交答案
</button>
<div v-if="practiceAnswered" class="feedback-box" :class="isPracticeCorrect ? 'feedback-correct' : 'feedback-wrong'">
<div v-if="isPracticeCorrect" style="font-weight: bold; margin-bottom: 5px;">🎉 正确!</div>
<div v-else style="font-weight: bold; margin-bottom: 5px;">💡 答案:{{ practiceQuestions[currentPracticeIndex].answer }}</div>
<div v-html="practiceQuestions[currentPracticeIndex].explanation"></div>
</div>
<button v-if="practiceAnswered" class="submit-btn" @click="nextPractice" style="margin-top: 10px;">
{{ currentPracticeIndex < 9 ? '下一题 →' : '完成练习 🎯' }}
</button>
</div>
</div>
<div v-else class="card" style="text-align: center; padding: 40px 20px;">
<div style="font-size: 60px; margin-bottom: 20px;">🏆</div>
<h2 style="color: #1E293B; margin-bottom: 10px;">练习完成!</h2>
<p style="font-size: 18px; color: #64748B; margin-bottom: 30px;">得分:{{ practiceScore }}/100</p>
<button class="submit-btn" @click="switchPage(4)">挑战杯赛真题 →</button>
</div>
</div>
<!-- Page 4: 10道杯赛真题 -->
<div v-show="currentPage === 4" class="page-container">
<div class="section-title">🏆 10道杯赛真题</div>
<div class="card" style="background: linear-gradient(135deg, #D1FAE5 0%, #A7F3D0 100%);">
<div style="font-size: 14px; color: #065F46; line-height: 1.6;">
<strong>💡 提示:</strong>这些题目来自华杯赛、希望杯等真题。<br>
需要灵活运用特定倍数约数的公式和技巧!
</div>
</div>
<div v-if="!olympiadDone">
<div class="question-card">
<div class="tag tag-emerald">🏆 杯赛真题 {{ currentOlympiadIndex + 1 }}/10</div>
<div class="question-text" v-html="olympiadQuestions[currentOlympiadIndex].question"></div>
<div v-if="olympiadQuestions[currentOlympiadIndex].hint"
style="background: #D1FAE5; padding: 12px; border-radius: 6px; margin-bottom: 10px; font-size: 13px;">
<strong>💡 提示:</strong>{{ olympiadQuestions[currentOlympiadIndex].hint }}
</div>
<input
type="text"
class="answer-input"
v-model="userOlympiadAnswer"
placeholder="输入答案"
@keyup.enter="checkOlympiadAnswer"
:disabled="olympiadAnswered">
<button class="submit-btn" @click="checkOlympiadAnswer" v-if="!olympiadAnswered">
提交答案
</button>
<div v-if="olympiadAnswered" class="feedback-box" :class="isOlympiadCorrect ? 'feedback-correct' : 'feedback-wrong'">
<div v-if="isOlympiadCorrect" style="font-weight: bold; margin-bottom: 5px;">🎉 正确!太棒了!</div>
<div v-else style="font-weight: bold; margin-bottom: 5px;">💡 正确答案:{{ olympiadQuestions[currentOlympiadIndex].answer }}</div>
<div style="margin-top: 10px;"><strong>详细解析:</strong></div>
<div v-html="olympiadQuestions[currentOlympiadIndex].explanation"></div>
</div>
<button v-if="olympiadAnswered" class="submit-btn" @click="nextOlympiad" style="margin-top: 10px;">
{{ currentOlympiadIndex < 9 ? '下一题 →' : '查看成绩 📚' }}
</button>
</div>
</div>
<div v-else class="card" style="text-align: center; padding: 40px 20px;">
<div style="font-size: 60px; margin-bottom: 20px;">🥇</div>
<h2 style="color: #1E293B; margin-bottom: 10px;">杯赛真题通关!</h2>
<p style="font-size: 18px; color: #64748B; margin-bottom: 30px;">得分:{{ olympiadScore }}/100</p>
<p style="font-size: 14px; color: #64748B;">你已经掌握了特定倍数的约数个数!</p>
</div>
</div>
</div>
<!-- 底部导航 -->
<div class="bottom-nav">
<div class="nav-item" :class="{active: currentPage === 1}" @click="switchPage(1)">
<div class="nav-icon">📖</div>
<div class="nav-label">原理</div>
</div>
<div class="nav-item" :class="{active: currentPage === 2}" @click="switchPage(2)">
<div class="nav-icon">📚</div>
<div class="nav-label">例题</div>
</div>
<div class="nav-item" :class="{active: currentPage === 3}" @click="switchPage(3)">
<div class="nav-icon">✏️</div>
<div class="nav-label">练习</div>
</div>
<div class="nav-item" :class="{active: currentPage === 4}" @click="switchPage(4)">
<div class="nav-icon">🏆</div>
<div class="nav-label">杯赛</div>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
currentPage: 1,
theoryTab: 'review',
exampleIndex: 0,
exampleSteps: [0, 0, 0, 0, 0],
classicExamples: [
{
title: '例题1:直接应用',
question: '求 $N=900$ 的约数中,有多少个是 $15$ 的倍数。',
steps: [
{equation: '第1步:检查前提', explanation: '验证k是否整除N', text: '步骤1:检查前提条件'},
{equation: '$900 \\div 15 = 60$,成立 ✓', explanation: '15整除900', text: '步骤2:前提成立'},
{equation: '第2步:计算 $N/k$', explanation: '商已经算出', text: '步骤3:计算N/k'},
{equation: '$\\frac{900}{15} = 60$', explanation: '得到60', text: '步骤4:N/k=60'},
{equation: '第3步:分解 $N/k$', explanation: '质因数分解', text: '步骤5:分解60'},
{equation: '$60 = 2^2 \\cdot 3^1 \\cdot 5^1$', explanation: '标准形式', text: '步骤6:得到分解式'},
{equation: '第4步:计算约数个数', explanation: '套用公式', text: '步骤7:套用公式'},
{equation: '$\\tau(60) = (2+1)(1+1)(1+1)$', explanation: '各指数加1', text: '步骤8:计算'},
{equation: '= 3 × 2 × 2 = <span class="calc-highlight">12</span>', explanation: '最终答案', text: '步骤9:得出答案'}
],
answer: '<strong style="color: #10B981; font-size: 18px;">答案:12个</strong>',
voice: '求900的约数中,有多少个是15的倍数。第一步,检查前提。900除以15等于60,成立。第二步,计算N除以k,等于60。第三步,分解60,等于2的平方乘以3乘以5。第四步,计算约数个数。等于括号2加1括号乘以括号1加1括号乘以括号1加1括号,等于3乘以2乘以2,等于12。答案是12个。'
},
{
title: '例题2:质因数分解进阶',
question: '求 $N = 3600$ 的约数中,有多少个是 $30$ 的倍数。',
steps: [
{equation: '第1步:分解 $N$ 和 $k$', explanation: '分别分解', text: '步骤1:分解N和k'},
{equation: '$N = 3600 = 2^4 \\cdot 3^2 \\cdot 5^2$', explanation: 'N的分解', text: '步骤2:N的分解'},
{equation: '$k = 30 = 2^1 \\cdot 3^1 \\cdot 5^1$', explanation: 'k的分解', text: '步骤3:k的分解'},
{equation: '第2步:计算 $N/k$', explanation: '指数相减', text: '步骤4:计算N/k'},
{equation: '$\\frac{N}{k} = 2^{4-1} \\cdot 3^{2-1} \\cdot 5^{2-1}$', explanation: '指数法则', text: '步骤5:指数相减'},
{equation: '= $2^3 \\cdot 3^1 \\cdot 5^1$', explanation: '化简结果', text: '步骤6:化简'},
{equation: '第3步:计算约数个数', explanation: '套用公式', text: '步骤7:套用公式'},
{equation: '$\\tau(N/k) = (3+1)(1+1)(1+1)$', explanation: '各指数加1', text: '步骤8:计算'},
{equation: '= 4 × 2 × 2 = <span class="calc-highlight">16</span>', explanation: '最终答案', text: '步骤9:得出答案'}
],
answer: '<strong style="color: #10B981; font-size: 18px;">答案:16个</strong>',
voice: '求3600的约数中,有多少个是30的倍数。第一步,分解N和k。N等于2的4次方乘以3的平方乘以5的平方。k等于2乘以3乘以5。第二步,计算N除以k。用指数相减法,等于2的3次方乘以3乘以5。第三步,计算约数个数。等于4乘以2乘以2,等于16。答案是16个。'
},
{
title: '例题3:逆向问题',
question: '已知 $N = 2^a \\cdot 3^2 \\cdot 5^1$,且 $N$ 的约数中是 $6$ 的倍数的共有 $12$ 个。求 $a$ 的值。',
steps: [
{equation: '第1步:分解 $k$', explanation: '确定k', text: '步骤1:分解k'},
{equation: '$k = 6 = 2^1 \\cdot 3^1$', explanation: 'k的分解', text: '步骤2:k=2×3'},
{equation: '第2步:计算 $N/k$', explanation: '指数相减', text: '步骤3:计算N/k'},
{equation: '$\\frac{N}{k} = 2^{a-1} \\cdot 3^{2-1} \\cdot 5^1$', explanation: '含未知数a', text: '步骤4:含a的式子'},
{equation: '= $2^{a-1} \\cdot 3^1 \\cdot 5^1$', explanation: '化简', text: '步骤5:化简'},
{equation: '第3步:应用公式', explanation: '已知τ(N/k)=12', text: '步骤6:应用条件'},
{equation: '$\\tau(N/k) = 12$', explanation: '题目条件', text: '步骤7:题目条件'},
{equation: '$((a-1)+1)(1+1)(1+1) = 12$', explanation: '展开公式', text: '步骤8:展开'},
{equation: '$a \\cdot 4 = 12$', explanation: '化简方程', text: '步骤9:化简'},
{equation: '<span class="calc-highlight">$a = 3$</span>', explanation: '解方程', text: '步骤10:得出答案'}
],
answer: '<strong style="color: #10B981; font-size: 18px;">答案:a = 3</strong>',
voice: '已知N等于2的a次方乘以3的平方乘以5,且N的约数中是6的倍数的共有12个,求a的值。第一步,分解k。k等于6,等于2乘以3。第二步,计算N除以k,等于2的a减1次方乘以3乘以5。第三步,应用公式。约数个数等于12。展开得,a乘以4等于12。解得a等于3。'
},
{
title: '例题4:多重倍数(容斥原理)',
question: '求 $N=180$ 的约数中,有多少个是 $2$ 的倍数或 $3$ 的倍数。',
steps: [
{equation: '容斥原理公式', explanation: '集合运算', text: '步骤1:容斥原理'},
{equation: '$|A \\cup B| = |A| + |B| - |A \\cap B|$', explanation: '并集公式', text: '步骤2:公式'},
{equation: '第1步:是2的倍数 $|A|$', explanation: '计算集合A', text: '步骤3:计算|A|'},
{equation: '$\\tau(180/2) = \\tau(90) = 12$', explanation: '2的倍数', text: '步骤4:|A|=12'},
{equation: '第2步:是3的倍数 $|B|$', explanation: '计算集合B', text: '步骤5:计算|B|'},
{equation: '$\\tau(180/3) = \\tau(60) = 12$', explanation: '3的倍数', text: '步骤6:|B|=12'},
{equation: '第3步:是6的倍数 $|A \\cap B|$', explanation: '交集', text: '步骤7:计算交集'},
{equation: '$\\tau(180/6) = \\tau(30) = 8$', explanation: '6的倍数', text: '步骤8:交集=8'},
{equation: '第4步:计算并集', explanation: '代入公式', text: '步骤9:计算并集'},
{equation: '<span class="calc-highlight">$12 + 12 - 8 = 16$</span>', explanation: '最终答案', text: '步骤10:得出答案'}
],
answer: '<strong style="color: #10B981; font-size: 18px;">答案:16个</strong>',
voice: '求180的约数中,有多少个是2的倍数或3的倍数。使用容斥原理。并集等于A加B减交集。第一步,是2的倍数有12个。第二步,是3的倍数有12个。第三步,是6的倍数有8个。第四步,计算并集。12加12减8,等于16。答案是16个。'
},
{
title: '例题5:差集问题',
question: '求 $N=300$ 的约数中,有多少个是 $5$ 的倍数,但不是 $10$ 的倍数。',
steps: [
{equation: '第1步:是5的倍数(总数A)', explanation: '集合A', text: '步骤1:集合A'},
{equation: '$\\tau(300/5) = \\tau(60) = 12$', explanation: '5的倍数', text: '步骤2:A=12个'},
{equation: '第2步:是10的倍数(集合B)', explanation: '集合B', text: '步骤3:集合B'},
{equation: '$\\tau(300/10) = \\tau(30) = 8$', explanation: '10的倍数', text: '步骤4:B=8个'},
{equation: '第3步:分析关系', explanation: '包含关系', text: '步骤5:分析关系'},
{equation: '10的倍数一定是5的倍数', explanation: 'B ⊆ A', text: '步骤6:B包含于A'},
{equation: '所以答案是 $A - B$', explanation: '差集', text: '步骤7:差集公式'},
{equation: '第4步:计算', explanation: '代入数值', text: '步骤8:计算'},
{equation: '<span class="calc-highlight">$12 - 8 = 4$</span>', explanation: '最终答案', text: '步骤9:得出答案'}
],
answer: '<strong style="color: #10B981; font-size: 18px;">答案:4个</strong>',
voice: '求300的约数中,有多少个是5的倍数但不是10的倍数。第一步,是5的倍数有12个。第二步,是10的倍数有8个。第三步,分析关系。10的倍数一定是5的倍数,所以B包含于A。答案是A减B,12减8,等于4。答案是4个。'
}
],
currentPracticeIndex: 0,
practiceScore: 0,
practiceAnswered: false,
isPracticeCorrect: false,
userAnswer: '',
practiceDone: false,
practiceQuestions: [
{question: '求 $N=1000$ 的约数中,有多少个是 $20$ 的倍数', answer: '6', explanation: '$\\tau(1000/20) = \\tau(50) = \\tau(2^1 \\cdot 5^2)$<br>$= (1+1)(2+1) = <strong>6</strong>$'},
{question: '求 $N=168$ 的约数中,有多少个是 $8$ 的倍数', answer: '4', explanation: '$\\tau(168/8) = \\tau(21) = \\tau(3^1 \\cdot 7^1)$<br>$= (1+1)(1+1) = <strong>4</strong>$'},
{question: '求 $N=420$ 的约数中,有多少个是 $7$ 的倍数', answer: '12', explanation: '$\\tau(420/7) = \\tau(60) = \\tau(2^2 \\cdot 3^1 \\cdot 5^1)$<br>$= 3 \\times 2 \\times 2 = <strong>12</strong>$'},
{question: '求 $N=648$ 的约数中,有多少个是 $18$ 的倍数', answer: '9', explanation: '$648/18 = 36 = 2^2 \\cdot 3^2$<br>$\\tau(36) = (2+1)(2+1) = <strong>9</strong>$'},
{question: '求 $N=2450$ 的约数中,有多少个是 $50$ 的倍数', answer: '3', explanation: '$2450/50 = 49 = 7^2$<br>$\\tau(49) = 2+1 = <strong>3</strong>$'},
{question: '$N = 2^5 \\cdot 3^3 \\cdot 5^2$,求是10的倍数但不是20的倍数的约数个数', answer: '8', explanation: '$\\tau(N/10) - \\tau(N/20)$<br>$= \\tau(2^4 3^3 5^1) - \\tau(2^3 3^3 5^1)$<br>$= 40 - 32 = <strong>8</strong>$'},
{question: '已知 $N$ 的约数有24个,求 $N^2$ 的约数中是 $N$ 的倍数的约数个数', answer: '24', explanation: '$\\tau(N^2/N) = \\tau(N) = <strong>24</strong>$'},
{question: '已知 $N = 2^a \\cdot 3^2$,若是2的倍数的约数有12个,求 $a$', answer: '4', explanation: '$\\tau(N/2) = \\tau(2^{a-1} 3^2) = (a)(3) = 12$<br>$a = <strong>4</strong>$'},
{question: '$N$ 的约数中,是4的倍数的有8个,是6的倍数的有6个,求 $N$ 的最小值', answer: '120', explanation: '$N=120=2^3 \\cdot 3 \\cdot 5$<br>$\\tau(120/4)=8$, $\\tau(120/6)=6$ ✓<br>最小值:<strong>120</strong>'},
{question: '$N=2^a \\cdot 3^b$ 有12个约数,是18的倍数的有3个,求 $N$', answer: '72', explanation: '$(a+1)(b+1)=12$, $a(b-1)=3$<br>$a=3, b=2$<br>$N = 2^3 \\cdot 3^2 = <strong>72</strong>$'}
],
currentOlympiadIndex: 0,
olympiadScore: 0,
olympiadAnswered: false,
isOlympiadCorrect: false,
userOlympiadAnswer: '',
olympiadDone: false,
olympiadQuestions: [
{question: '四位数 $N = \\overline{3a2b}$ 是12的倍数,其约数中是4的倍数的有18个,求 $N$', answer: '3528', hint: 'τ(N/4)=18', explanation: '$\\tau(N/4)=18$<br>$N = 4 \\times 882 = <strong>3528</strong>$'},
{question: '$N$ 的约数中,是10的倍数的有6个,是15的倍数的有4个,求 $N$ 的最小值', answer: '120', hint: 'τ(N/10)=6, τ(N/15)=4', explanation: '$\\tau(N/10)=6$, $\\tau(N/15)=4$<br>最小满足:$N=<strong>120</strong>$'},
{question: '三位数 $N = 2^a \\cdot b^1$($b$ 是奇质数),是4的倍数的约数有6个,求最大的 $N$', answer: '976', hint: 'τ(N/4)=6 → a=4', explanation: '$\\tau(N/4)=6$ → $a=4$<br>$N=16b \\le 999$ → $b \\le 62$<br>最大奇质数 $b=61$<br>$N = 16 \\times 61 = <strong>976</strong>$'},
{question: '求1到100中,有多少个 $N$ 满足约数中是6的倍数的恰好有4个', answer: '5', hint: 'τ(N/6)=4', explanation: '$\\tau(N/6)=4$<br>满足的N:48, 36, 60, 84, 90<br>共 <strong>5</strong> 个'},
{question: '四位数 $N$ 是150的倍数,是150的倍数的约数有10个,求 $N$ 的最小值', answer: '7200', hint: 'τ(N/150)=10', explanation: '$\\tau(N/150)=10$<br>$N/150$ 最小为 $2^4 \\cdot 3 = 48$<br>$N = 150 \\times 48 = <strong>7200</strong>$'},
{question: '$N = 2^a \\cdot 3^b$,是4的倍数的约数有24个,是9的倍数的有18个,求 $\\tau(N)$', answer: '24', hint: '两个方程求a,b', explanation: '$(a-1)(b+1)=24$<br>$(a+1)(b-1)=18$<br>解得 $a=5, b=3$<br>$\\tau(N) = 6 \\times 4 = <strong>24</strong>$'},
{question: '整数 $N$ 的所有约数和 $\\sigma(N)=124$,求是2的倍数的约数个数', answer: '8', hint: 'σ(N)=124 → N=?', explanation: '$\\sigma(N)=124$ → $N = 2^4 \\cdot 3 = 48$<br>$\\tau(48/2) = \\tau(24) = <strong>8</strong>$'},
{question: '$1000!$ 的约数中,是50的倍数的约数有多少个(简化形式:输入 994)', answer: '994', hint: '勒让德定理', explanation: '$1000! = 2^{994} \\cdot 5^{249} \\cdot \\ldots$<br>$\\tau(1000!/50)$ 中2的因子贡献:<strong>994</strong>'},
{question: '$N$ 的约数中是3的倍数的有4个,是4的倍数的有3个,求 $\\sigma(N)$', answer: '195', hint: 'τ(N/3)=4, τ(N/4)=3', explanation: '$\\tau(N/3)=4$, $\\tau(N/4)=3$<br>$N = 2^3 \\cdot 3^2 = 72$<br>$\\sigma(72) = 15 \\times 13 = <strong>195</strong>$'},
{question: '1000以内,有多少个 $N$ 满足约数中是20的倍数的有3个', answer: '4', hint: 'τ(N/20)=3 → N/20=p²', explanation: '$\\tau(N/20)=3$ → $N/20=p^2$<br>$N=20p^2 \\le 1000$<br>$p=2,3,5,7$:80,180,500,980<br>共 <strong>4</strong> 个'}
]
}
},
methods: {
speak(text) {
if (window.speechSynthesis) window.speechSynthesis.cancel();
const isWeChat = /MicroMessenger/i.test(navigator.userAgent);
if (isWeChat) {
let audio = document.getElementById('tts-audio');
if (!audio) {
audio = document.createElement('audio'); audio.id = 'tts-audio'; audio.style.display = 'none';
document.body.appendChild(audio);
}
const url = `https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/tts.php?text=${encodeURIComponent(text)}&t=${Date.now()}`;
audio.src = url;
audio.play().catch(e => { if(window.WeixinJSBridge) window.WeixinJSBridge.invoke('getNetworkType',{},()=>audio.play()); });
} else {
if (window.speechSynthesis) {
const u = new SpeechSynthesisUtterance(text); u.lang = 'zh-CN'; u.rate = 0.9;
window.speechSynthesis.speak(u);
}
}
},
speakReview() {
this.speak('知识回顾。约数个数公式。对一个正整数N进行质因数分解,N等于p1的a1次方乘以p2的a2次方,一直到pn的an次方。那么N的所有约数的个数,等于括号a1加1括号乘以括号a2加1括号,一直到括号an加1括号。例如72等于2的3次方乘以3的平方,约数个数等于4乘以3,等于12个。');
},
speakCore() {
this.speak('核心思想:把k提出来。我们要求N的约数中有多少个是k的倍数。前提条件,如果k不是N的约数,那么答案直接是0。推导过程,设约数d等于k乘以d撇。因为d整除N,所以k乘以d撇整除N。两边同时除以k,得到d撇整除N除以k。结论,k的倍数约数个数等于N除以k的约数个数。核心公式,k倍数约数个数等于N除以k的约数个数。');
},
speakExample() {
this.speak('举例详解。N等于72等于2的3次方乘以3的平方,求72的约数中有多少是12的倍数。第一步,检查前提,72除以12等于6,前提成立。第二步,计算N除以k等于6。第三步,分解6等于2乘以3。第四步,应用约数个数公式,等于2乘以2,等于4。最终结论,72中是12的倍数的约数有4个。');
},
speakAdvanced() {
this.speak('进阶视角:质因数分解直接法。N等于2的3次方乘以3的平方,k等于2的平方乘以3。我们寻找的约数d必须是k的倍数,这意味着d的质因数分解式中,2的指数至少是2,3的指数至少是1。对于2的指数x,范围是2到3,有2种取法。对于3的指数y,范围是1到2,有2种取法。总数等于2乘以2,等于4。这与公式法的结果完全一致。');
},
speakExampleVoice(index) {
const voice = this.classicExamples[index].voice;
if (voice) this.speak(voice);
},
switchPage(page) {
if (window.speechSynthesis) window.speechSynthesis.cancel();
this.currentPage = page;
window.scrollTo(0, 0);
this.$nextTick(() => this.renderMath());
},
renderMath() {
if (typeof renderMathInElement !== 'undefined') {
setTimeout(() => {
renderMathInElement(document.body, {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}
],
throwOnError: false
});
}, 100);
}
},
animateReview() {
const container = document.getElementById('review-demo');
container.innerHTML = '';
const steps = [
{eq: '$72 = 2^3 \\times 3^2$', exp: '质因数分解'},
{eq: '指数:$a_1=3, a_2=2$', exp: '提取指数'},
{eq: '$\\tau(72) = (3+1)(2+1)$', exp: '套用公式'},
{eq: '= 4 × 3 = <span class="calc-highlight">12</span>', exp: '计算结果'}
];
steps.forEach((step, i) => {
const div = document.createElement('div');
div.className = 'calc-step';
div.innerHTML = `<div class="calc-equation">${step.eq}</div><div class="calc-explanation">${step.exp}</div>`;
container.appendChild(div);
gsap.fromTo(div, {opacity: 0, y: 20}, {
opacity: 1, y: 0, duration: 0.5, delay: i * 0.8,
onStart: () => {
div.classList.add('active');
document.getElementById('review-text').textContent = `步骤${i+1}:${step.exp}`;
}
});
});
setTimeout(() => this.renderMath(), 100);
},
animateCore() {
const container = document.getElementById('core-demo');
container.innerHTML = '';
const steps = [
{eq: '设约数 $d = k \\cdot d\'$', exp: 'd是k的倍数'},
{eq: '因为 $d \\mid N$', exp: 'd整除N'},
{eq: '所以 $(k \\cdot d\') \\mid N$', exp: '代入'},
{eq: '两边除以 $k$', exp: '化简'},
{eq: '$d\' \\mid \\frac{N}{k}$', exp: '关键结论'},
{eq: '结论:$\\tau_{k\\text{-倍数}}(N) = \\tau\\left(\\frac{N}{k}\\right)$', exp: '核心公式'}
];
steps.forEach((step, i) => {
const div = document.createElement('div');
div.className = 'calc-step';
div.innerHTML = `<div class="calc-equation">${step.eq}</div><div class="calc-explanation">${step.exp}</div>`;
container.appendChild(div);
gsap.fromTo(div, {opacity: 0, y: 20}, {
opacity: 1, y: 0, duration: 0.5, delay: i * 0.8,
onStart: () => {
div.classList.add('active');
document.getElementById('core-text').textContent = `步骤${i+1}:${step.exp}`;
}
});
});
setTimeout(() => this.renderMath(), 100);
},
animateExample() {
const container = document.getElementById('example-demo');
container.innerHTML = '';
const steps = [
{eq: '检查:$72 \\div 12 = 6$ ✓', exp: '前提成立'},
{eq: '$\\frac{N}{k} = \\frac{72}{12} = 6$', exp: '计算N/k'},
{eq: '$6 = 2^1 \\times 3^1$', exp: '分解'},
{eq: '$\\tau(6) = (1+1)(1+1)$', exp: '套用公式'},
{eq: '= 2 × 2 = <span class="calc-highlight">4</span>', exp: '最终答案'}
];
steps.forEach((step, i) => {
const div = document.createElement('div');
div.className = 'calc-step';
div.innerHTML = `<div class="calc-equation">${step.eq}</div><div class="calc-explanation">${step.exp}</div>`;
container.appendChild(div);
gsap.fromTo(div, {opacity: 0, y: 20}, {
opacity: 1, y: 0, duration: 0.5, delay: i * 0.8,
onStart: () => {
div.classList.add('active');
document.getElementById('example-text').textContent = `步骤${i+1}:${step.exp}`;
}
});
});
setTimeout(() => this.renderMath(), 100);
},
animateVerify() {
const container = document.getElementById('verify-demo');
container.innerHTML = '';
const allDivisors = [1, 2, 3, 4, 6, 8, 9, 12, 18, 24, 36, 72];
const multiplesOf12 = [12, 24, 36, 72];
const grid = document.createElement('div');
grid.className = 'divisor-grid';
container.appendChild(grid);
allDivisors.forEach((d, i) => {
const box = document.createElement('div');
box.className = 'divisor-box';
box.textContent = d;
if (multiplesOf12.includes(d)) {
box.classList.add('divisor-multiple');
} else {
box.classList.add('divisor-normal');
}
grid.appendChild(box);
gsap.fromTo(box, {opacity: 0, scale: 0}, {
opacity: 1, scale: 1, duration: 0.3, delay: i * 0.15
});
});
setTimeout(() => {
document.getElementById('verify-text').textContent = '72共12个约数,其中4个是12的倍数(金色边框)';
}, 2000);
},
animateAdvanced() {
const container = document.getElementById('advanced-demo');
container.innerHTML = '';
const steps = [
{eq: '设 $d = 2^x \\times 3^y$', exp: 'd的形式'},
{eq: '$d$ 是 $12=2^2 \\times 3^1$ 的倍数', exp: '倍数条件'},
{eq: '$x \\ge 2$, $y \\ge 1$', exp: '指数下界'},
{eq: '$d$ 是 $72=2^3 \\times 3^2$ 的约数', exp: '约数条件'},
{eq: '$x \\le 3$, $y \\le 2$', exp: '指数上界'},
{eq: '2的指数:$2 \\le x \\le 3$ (2种)', exp: 'x可取2,3'},
{eq: '3的指数:$1 \\le y \\le 2$ (2种)', exp: 'y可取1,2'},
{eq: '总数 = 2 × 2 = <span class="calc-highlight">4</span>', exp: '乘法原理'}
];
steps.forEach((step, i) => {
const div = document.createElement('div');
div.className = 'calc-step';
div.innerHTML = `<div class="calc-equation">${step.eq}</div><div class="calc-explanation">${step.exp}</div>`;
container.appendChild(div);
gsap.fromTo(div, {opacity: 0, y: 20}, {
opacity: 1, y: 0, duration: 0.5, delay: i * 0.7,
onStart: () => {
div.classList.add('active');
document.getElementById('advanced-text').textContent = `步骤${i+1}:${step.exp}`;
}
});
});
setTimeout(() => this.renderMath(), 100);
},
switchExample(index) {
this.exampleIndex = index;
this.$nextTick(() => this.renderMath());
},
nextExampleStep(index) {
if (this.exampleSteps[index] < this.classicExamples[index].steps.length - 1) {
this.exampleSteps[index]++;
this.$nextTick(() => this.renderMath());
}
},
prevExampleStep(index) {
if (this.exampleSteps[index] > 0) {
this.exampleSteps[index]--;
}
},
resetExampleStep(index) {
this.exampleSteps[index] = 0;
},
checkPracticeAnswer() {
if (this.practiceAnswered) return;
const correctAnswer = this.practiceQuestions[this.currentPracticeIndex].answer.toLowerCase().trim();
const userAnswer = this.userAnswer.toLowerCase().trim().replace(/\s+/g, '');
this.practiceAnswered = true;
this.isPracticeCorrect = userAnswer === correctAnswer;
if (this.isPracticeCorrect) {
this.practiceScore += 10;
}
this.$nextTick(() => this.renderMath());
},
nextPractice() {
if (this.currentPracticeIndex < 9) {
this.currentPracticeIndex++;
this.practiceAnswered = false;
this.userAnswer = '';
this.$nextTick(() => this.renderMath());
} else {
this.practiceDone = true;
}
},
checkOlympiadAnswer() {
if (this.olympiadAnswered) return;
const correctAnswer = this.olympiadQuestions[this.currentOlympiadIndex].answer.toLowerCase().trim();
const userAnswer = this.userOlympiadAnswer.toLowerCase().trim().replace(/\s+/g, '');
this.olympiadAnswered = true;
this.isOlympiadCorrect = userAnswer === correctAnswer;
if (this.isOlympiadCorrect) {
this.olympiadScore += 10;
}
this.$nextTick(() => this.renderMath());
},
nextOlympiad() {
if (this.currentOlympiadIndex < 9) {
this.currentOlympiadIndex++;
this.olympiadAnswered = false;
this.userOlympiadAnswer = '';
this.$nextTick(() => this.renderMath());
} else {
this.olympiadDone = true;
}
}
},
mounted() {
this.renderMath();
}
}).mount('#app');
</script>
</body>
</html>
💡 这段代码完全由 AI 生成。
登录后可复制完整代码