<!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>
<link rel="stylesheet" href="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/katex/katex.min.css">
<script defer src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/katex/katex.min.js"></script>
<script defer src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/katex/auto-render.min.js"></script>
<script src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/js/vue.global.prod.js"></script>
<script src="https://www.xinghuo.tv/wp-content/themes/xinghuo-tv/assets/js/gsap.min.js"></script>
<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, #EF4444 0%, #DC2626 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: 80px;
text-align: center;
}
.top-tab.active {
background: white;
color: #DC2626;
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: #EF4444; }
.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-red { background: #FEE2E2; color: #DC2626; }
.type-card {
background: linear-gradient(135deg, #FEE2E2 0%, #FECACA 100%);
border: 2px solid #EF4444;
border-radius: 12px;
padding: 20px;
margin-bottom: 15px;
}
.type-title {
font-size: 16px;
font-weight: bold;
color: #991B1B;
margin-bottom: 10px;
}
.type-core {
background: white;
padding: 12px;
border-radius: 8px;
margin: 10px 0;
font-size: 14px;
}
.keyword-box {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 10px;
}
.keyword {
background: #FBBF24;
color: #78350F;
padding: 4px 10px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
}
.speak-btn {
background: linear-gradient(135deg, #EF4444 0%, #DC2626 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(239, 68, 68, 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: #EF4444;
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: #EF4444;
background: rgba(239, 68, 68, 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;
}
.timeline {
width: 100%;
height: 80px;
background: rgba(255,255,255,0.1);
border-radius: 10px;
position: relative;
margin: 10px 0;
}
.timeline-mark {
position: absolute;
width: 3px;
height: 100%;
background: #FCD34D;
opacity: 0;
}
.timeline-label {
position: absolute;
bottom: -25px;
font-size: 12px;
color: #FCD34D;
font-weight: bold;
transform: translateX(-50%);
}
.grid-demo {
display: grid;
gap: 2px;
background: rgba(255,255,255,0.2);
padding: 10px;
border-radius: 10px;
}
.grid-cell {
background: #3B82F6;
aspect-ratio: 1;
border-radius: 4px;
opacity: 0;
}
/* 练习题样式 */
.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: #EF4444;
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;
}
.example-item {
border: 2px solid #E2E8F0;
border-radius: 10px;
margin-bottom: 12px;
overflow: hidden;
}
.example-header {
padding: 15px;
background: #F8FAFC;
font-weight: bold;
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
font-size: 14px;
}
.example-content {
padding: 15px;
border-top: 1px solid #E2E8F0;
background: white;
line-height: 1.8;
font-size: 13px;
color: #334155;
display: none;
}
.example-item.active .example-content { display: block; }
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
@keyframes slideIn {
from { transform: translateX(-20px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
</style><script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "\\[", right: "\\]", display: true},
{left: "$", right: "$", display: false},
{left: "\\(", right: "\\)", display: false}
],
throwOnError: false
});
});
</script>
</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: typeTab === 'cycle'}" @click="typeTab = 'cycle'">
周期相遇
</div>
<div class="top-tab" :class="{active: typeTab === 'cut'}" @click="typeTab = 'cut'">
裁割拼接
</div>
<div class="top-tab" :class="{active: typeTab === 'remainder'}" @click="typeTab = 'remainder'">
余数问题
</div>
<div class="top-tab" :class="{active: typeTab === 'reverse'}" @click="typeTab = 'reverse'">
逆向推导
</div>
</div>
<div class="page-container">
<!-- 周期与相遇 -->
<div v-show="typeTab === 'cycle'">
<div class="section-title">🔄 题型1:周期与相遇问题</div>
<div class="type-card">
<div class="type-title">考查核心</div>
<div class="type-core">
寻找所有<strong>周期</strong>或<strong>时间间隔</strong>的<strong style="color: #EF4444;">最小公倍数 LCM</strong>
</div>
<div class="keyword-box">
<span class="keyword">间隔</span>
<span class="keyword">同时</span>
<span class="keyword">相遇</span>
<span class="keyword">下一次</span>
<span class="keyword">再次</span>
</div>
</div>
<div class="card">
<div class="tag tag-blue">经典例题:三盏信号灯</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
红灯每隔<strong>10秒</strong>亮一次,黄灯每隔<strong>12秒</strong>亮一次,绿灯每隔<strong>15秒</strong>亮一次。<br>
如果它们在某一时刻同时亮起,请问<strong>最少再过多少秒</strong>它们会再次同时亮起?
</p>
<div class="step-controls">
<button class="step-btn" @click="animateCycle">▶️ 演示解题过程</button>
</div>
<div class="anim-stage">
<div class="visual-demo" id="cycle-demo">
<!-- 动画将在这里生成 -->
</div>
<div class="anim-text" id="cycle-text">点击按钮开始演示</div>
</div>
</div>
<div class="card">
<div class="tag tag-green">解题思路</div>
<div style="font-size: 13px; color: #334155; line-height: 1.8;">
<p><strong>步骤1:</strong>识别题型 → 看到"同时"、"再次"关键词</p>
<p><strong>步骤2:</strong>提取周期 → 10秒、12秒、15秒</p>
<p><strong>步骤3:</strong>求LCM → $[10, 12, 15]$</p>
<p><strong>步骤4:</strong>计算答案 → 60秒</p>
</div>
</div>
<button class="speak-btn" @click="speakCycle">
🔊 听讲解
</button>
</div>
<!-- 裁割与拼接 -->
<div v-show="typeTab === 'cut'">
<div class="section-title">✂️ 题型2:裁割与拼接问题</div>
<div class="type-card">
<div class="type-title">考查核心</div>
<div class="type-core">
寻找所有<strong>长度</strong>或<strong>尺寸</strong>的<strong style="color: #EF4444;">最大公约数 GCD</strong>
</div>
<div class="keyword-box">
<span class="keyword">最大</span>
<span class="keyword">最长</span>
<span class="keyword">相等</span>
<span class="keyword">不浪费</span>
<span class="keyword">无剩余</span>
</div>
</div>
<div class="card">
<div class="tag tag-blue">经典例题:正方形裁剪</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
有一张长<strong>105厘米</strong>,宽<strong>70厘米</strong>的长方形纸。<br>
现在要把它剪成若干个<strong>大小相等的最大正方形</strong>,且<strong>不能有剩余</strong>。<br>
请问正方形的边长是多少厘米?
</p>
<div class="step-controls">
<button class="step-btn" @click="animateCut">▶️ 演示解题过程</button>
</div>
<div class="anim-stage">
<div class="visual-demo" id="cut-demo">
<!-- 动画将在这里生成 -->
</div>
<div class="anim-text" id="cut-text">点击按钮开始演示</div>
</div>
</div>
<div class="card">
<div class="tag tag-green">解题思路</div>
<div style="font-size: 13px; color: #334155; line-height: 1.8;">
<p><strong>步骤1:</strong>识别题型 → 看到"最大"、"无剩余"关键词</p>
<p><strong>步骤2:</strong>提取尺寸 → 105cm、70cm</p>
<p><strong>步骤3:</strong>求GCD → $(105, 70)$</p>
<p><strong>步骤4:</strong>计算答案 → 35厘米</p>
</div>
</div>
<button class="speak-btn" @click="speakCut">
🔊 听讲解
</button>
</div>
<!-- 余数问题 -->
<div v-show="typeTab === 'remainder'">
<div class="section-title">🔢 题型3:余数问题</div>
<div class="type-card">
<div class="type-title">考查核心</div>
<div class="type-core">
利用<strong style="color: #EF4444;">余同取余</strong>或<strong style="color: #EF4444;">差同减差</strong>转化为LCM问题
</div>
<div class="keyword-box">
<span class="keyword">除以...余...</span>
<span class="keyword">余数相同</span>
<span class="keyword">差相同</span>
</div>
</div>
<div class="card">
<div class="tag tag-purple">公式1:余同取余</div>
<div style="background: #F3E8FF; padding: 15px; border-radius: 8px; margin: 10px 0; text-align: center;">
如果余数都是 $r$,则:<br>
<strong style="color: #7C3AED; font-size: 16px;">$N = [A, B, C] \times k + r$</strong>
</div>
<p style="font-size: 13px; color: #64748B;">例:除以3余1,除以5余1 → $N = [3,5]k + 1 = 15k + 1$</p>
</div>
<div class="card">
<div class="tag tag-orange">公式2:差同减差</div>
<div style="background: #FFEDD5; padding: 15px; border-radius: 8px; margin: 10px 0; text-align: center;">
如果差都是 $d$,则:<br>
<strong style="color: #C2410C; font-size: 16px;">$N = [A, B, C] \times k - d$</strong>
</div>
<p style="font-size: 13px; color: #64748B;">例:除以5余4,除以7余6 → 差都是1 → $N = [5,7]k - 1 = 35k - 1$</p>
</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$,它被<strong>3除余1</strong>,被<strong>4除余1</strong>,被<strong>5除余1</strong>。<br>
请问满足这个条件的<strong>最小自然数</strong> $N$ 是多少?
</p>
<div class="step-controls">
<button class="step-btn" @click="animateRemainder">▶️ 演示解题过程</button>
</div>
<div class="anim-stage">
<div class="calc-demo" id="remainder-demo">
<!-- 动画将在这里生成 -->
</div>
<div class="anim-text" id="remainder-text">点击按钮开始演示</div>
</div>
</div>
<button class="speak-btn" @click="speakRemainder">
🔊 听讲解
</button>
</div>
<!-- 逆向推导 -->
<div v-show="typeTab === 'reverse'">
<div class="section-title">🔍 题型4:逆向推导题</div>
<div class="type-card">
<div class="type-title">考查核心</div>
<div class="type-core">
利用公式 <strong style="color: #EF4444;">$a \times b = \text{GCD} \times \text{LCM}$</strong> 和<strong>互质设未知数</strong>
</div>
<div class="keyword-box">
<span class="keyword">已知GCD和LCM</span>
<span class="keyword">求原数</span>
<span class="keyword">互质</span>
</div>
</div>
<div class="card">
<div class="tag tag-red">核心方法</div>
<div style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
<p><strong>步骤1:</strong>设 $a = \text{GCD} \times x$,$b = \text{GCD} \times y$</p>
<p><strong>步骤2:</strong>其中 $x, y$ 互质(重要!)</p>
<p><strong>步骤3:</strong>利用 $\text{GCD} \times x \times y = \text{LCM}$ 求 $xy$</p>
<p><strong>步骤4:</strong>分解 $xy$,找所有互质数对</p>
<p><strong>步骤5:</strong>代回求 $a, b$</p>
</div>
</div>
<div class="card">
<div class="tag tag-blue">经典例题:求原数</div>
<p style="font-size: 14px; color: #334155; line-height: 1.8; margin-top: 10px;">
两个数的最大公约数是<strong>8</strong>,最小公倍数是<strong>120</strong>。<br>
请问满足条件的这两个数可能是多少?
</p>
<div class="step-controls">
<button class="step-btn" @click="animateReverse">▶️ 演示解题过程</button>
</div>
<div class="anim-stage">
<div class="calc-demo" id="reverse-demo">
<!-- 动画将在这里生成 -->
</div>
<div class="anim-text" id="reverse-text">点击按钮开始演示</div>
</div>
</div>
<button class="speak-btn" @click="speakReverse">
🔊 听讲解
</button>
</div>
</div>
</div>
<!-- Page 2: 经典例题 -->
<div v-show="currentPage === 2" class="page-container">
<div class="section-title">📚 5道经典例题</div>
<div class="example-item" :class="{active: activeExample === index}" v-for="(ex, index) in classicExamples" :key="index">
<div class="example-header" @click="toggleExample(index)">
<span>{{ ex.title }}</span>
<span>{{ activeExample === index ? '▲' : '▼' }}</span>
</div>
<div class="example-content">
<div class="tag" :class="'tag-' + ex.type">{{ ex.typeName }}</div>
<div style="font-weight: bold; margin: 10px 0;" v-html="ex.question"></div>
<div style="background: #F0FDF4; padding: 15px; border-radius: 8px; margin: 10px 0; border-left: 3px solid #10B981;" v-html="ex.solution"></div>
</div>
</div>
</div>
<!-- Page 3: 综合练习 -->
<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: 杯赛真题 -->
<div v-show="currentPage === 4" class="page-container">
<div class="section-title">🏆 10道杯赛真题</div>
<div class="card" style="background: linear-gradient(135deg, #FEF3C7 0%, #FDE68A 100%);">
<div style="font-size: 14px; color: #92400E; line-height: 1.6;">
<strong>💡 提示:</strong>这些题目来自华杯赛、希望杯、迎春杯等真题。<br>
需要综合运用四大题型的解题方法!
</div>
</div>
<div v-if="!olympiadDone">
<div class="question-card">
<div class="tag tag-red">🏆 杯赛真题 {{ currentOlympiadIndex + 1 }}/10</div>
<div class="question-text" v-html="olympiadQuestions[currentOlympiadIndex].question"></div>
<div v-if="olympiadQuestions[currentOlympiadIndex].hint"
style="background: #FEF3C7; 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,
typeTab: 'cycle',
// 例题展开
activeExample: null,
// 5道经典例题
classicExamples: [
{
title: '例题1:三盏信号灯问题(周期与相遇)',
type: 'blue',
typeName: '周期与相遇',
question: '三盏信号灯分别每 $6$ 秒、$8$ 秒和 $12$ 秒闪烁一次。如果它们在某一时刻同时闪烁,那么至少经过多少秒,它们会再次同时闪烁?',
solution: '<strong>解题过程:</strong><br>' +
'1️⃣ <strong>判断题型:</strong>周期与相遇问题,求最小公倍数<br>' +
'2️⃣ <strong>计算:</strong>求 $[6, 8, 12]$<br>' +
'• $6 = 2 \\times 3$<br>' +
'• $8 = 2^3$<br>' +
'• $12 = 2^2 \\times 3$<br>' +
'3️⃣ <strong>LCM公式:</strong>$[6, 8, 12] = 2^3 \\times 3 = 24$<br>' +
'<strong style="color: #EF4444; font-size: 16px;">答案:至少经过 24 秒</strong>'
},
{
title: '例题2:长方形裁剪(裁割与拼接)',
type: 'green',
typeName: '裁割与拼接',
question: '有一个长 $36$ 厘米,宽 $48$ 厘米的长方形木板。要将其裁成若干个面积最大的正方形木板,且不能有剩余。正方形的边长是多少?',
solution: '<strong>解题过程:</strong><br>' +
'1️⃣ <strong>判断题型:</strong>裁割问题,求最大公约数<br>' +
'2️⃣ <strong>计算:</strong>求 $(36, 48)$<br>' +
'• $36 = 2^2 \\times 3^2$<br>' +
'• $48 = 2^4 \\times 3^1$<br>' +
'3️⃣ <strong>GCD公式:</strong>$(36, 48) = 2^2 \\times 3 = 12$<br>' +
'<strong style="color: #EF4444; font-size: 16px;">答案:正方形边长为 12 厘米</strong>'
},
{
title: '例题3:余同取余(余数问题)',
type: 'purple',
typeName: '余数问题',
question: '一个数 $N$ 除以 $3$ 余 $2$,除以 $5$ 余 $2$,除以 $7$ 余 $2$。求 $N$ 的最小值。',
solution: '<strong>解题过程:</strong><br>' +
'1️⃣ <strong>判断题型:</strong>余数问题(余同取余)<br>' +
'2️⃣ <strong>原理:</strong>因为余数相同,所以 $N - 2$ 是 $3, 5, 7$ 的公倍数<br>' +
'• $N - 2 = [3, 5, 7] \\times k$<br>' +
'3️⃣ <strong>计算LCM:</strong>$3, 5, 7$ 互质,所以 $[3, 5, 7] = 105$<br>' +
'4️⃣ <strong>求解N:</strong>$N = 105 \\times 1 + 2 = 107$(取$k=1$)<br>' +
'<strong style="color: #EF4444; font-size: 16px;">答案:107</strong>'
},
{
title: '例题4:逆向推导(求原数)',
type: 'red',
typeName: '逆向推导',
question: '已知两个自然数 $A$ 和 $B$ 的最大公约数 $(A, B) = 6$,最小公倍数 $[A, B] = 72$。求 $A$ 和 $B$ 这两个数。',
solution: '<strong>解题过程:</strong><br>' +
'1️⃣ <strong>设未知数:</strong>设 $A = 6x, B = 6y$,其中 $x, y$ 互质<br>' +
'2️⃣ <strong>套公式:</strong>$A \\times B = (A, B) \\times [A, B]$<br>' +
'• $(6x) \\times (6y) = 6 \\times 72$<br>' +
'• $36xy = 432$<br>' +
'• $xy = 12$<br>' +
'3️⃣ <strong>找互质数对:</strong>$(1, 12)$ 和 $(3, 4)$<br>' +
'4️⃣ <strong>代回求解:</strong><br>' +
'• $(6 \\times 1, 6 \\times 12) = (6, 72)$<br>' +
'• $(6 \\times 3, 6 \\times 4) = (18, 24)$<br>' +
'<strong style="color: #EF4444; font-size: 16px;">答案:(6, 72) 或 (18, 24)</strong>'
},
{
title: '例题5:分数化简(辗转相除法)',
type: 'orange',
typeName: '辗转相除法',
question: '将分数 $\\frac{1309}{2431}$ 化为最简分数。',
solution: '<strong>解题过程:</strong><br>' +
'1️⃣ <strong>辗转相除:</strong><br>' +
'• $2431 \\div 1309 = 1$ 余 $1122$<br>' +
'• $1309 \\div 1122 = 1$ 余 $187$<br>' +
'• $1122 \\div 187 = 6$ 余 $0$ ✓<br>' +
'2️⃣ <strong>求GCD:</strong>最大公约数是 $187$<br>' +
'3️⃣ <strong>化简:</strong><br>' +
'• 分子:$1309 \\div 187 = 7$<br>' +
'• 分母:$2431 \\div 187 = 13$<br>' +
'<strong style="color: #EF4444; font-size: 16px;">答案:$\\frac{7}{13}$</strong>'
}
],
// 练习题
currentPracticeIndex: 0,
practiceScore: 0,
practiceAnswered: false,
isPracticeCorrect: false,
userAnswer: '',
practiceDone: false,
practiceQuestions: [
{question: '求 $(114, 171)$', answer: '57', explanation: '使用辗转相除法:$171 \\div 114 = 1$ 余 $57$ → $114 \\div 57 = 2$ 余 $0$ → GCD = 57'},
{question: '已知 $(a, b) = 15$,$a=90$。求 $[a, b]$ 的最小值', answer: '90', explanation: '倍数关系:$90$ 是 $15$ 的倍数,为了LCM最小,$b$ 应是 $a$ 的因数。当 $b=90$ 时,$[90, 90]=90$ 最小'},
{question: '求 $\\text{GCD}(1000, 150)$', answer: '50', explanation: '同倍缩放:$\\text{GCD}(10 \\times 100, 10 \\times 15) = 10 \\times (100, 15) = 10 \\times 5 = 50$'},
{question: '两个数 $A$ 和 $B$ 互质,它们的和是 $10$,求 $[A, B]$ 最大是多少', answer: '21', explanation: '互质且 $A+B=10$ 的数对:$(1, 9)$ 和 $(3, 7)$<br>$[1, 9] = 9$,$[3, 7] = 21$<br>最大是 21'},
{question: '将分数 $\\frac{105}{168}$ 化为最简分数(输入分子)', answer: '5', explanation: '$\\text{GCD}(105, 168) = 21$<br>$105 \\div 21 = 5$,$168 \\div 21 = 8$<br>答案:$\\frac{5}{8}$'},
{question: '已知 $[a, b] = 60$,$(a, b) = 5$,求 $a \\times b$', answer: '300', explanation: '使用乘积公式:$a \\times b = (a, b) \\times [a, b] = 5 \\times 60 = 300$'},
{question: '$A$ 是 $B$ 的 $3$ 倍,$B=12$,求 $(A, B)$', answer: '12', explanation: '倍数关系:$(A, B)$ = 较小的数 = $B = 12$'},
{question: '求 $\\text{LCM}(12, 18, 24)$', answer: '72', explanation: '先求两个:$[12, 18] = 36$<br>再求:$[36, 24] = 72$'},
{question: '两个数的最大公约数是 $7$,乘积是 $294$,求最小公倍数', answer: '42', explanation: '使用公式:$[a, b] = (a \\times b) \\div (a, b) = 294 \\div 7 = 42$'},
{question: '一个数除以2、3、5都余1,求这个数在100内的最小值', answer: '31', explanation: '余同取余:$N = [2, 3, 5]k + 1 = 30k + 1$<br>$k=1$ 时,$N=31$'}
],
// 杯赛真题
currentOlympiadIndex: 0,
olympiadScore: 0,
olympiadAnswered: false,
isOlympiadCorrect: false,
userOlympiadAnswer: '',
olympiadDone: false,
olympiadQuestions: [
{
question: '(希望杯)甲乙丙三人同时从同一起点反向绕一圈长 $400$ 米的跑道跑步,速度分别为 $60$ 米/分,$80$ 米/分,$120$ 米/分。他们至少多少分钟后在起点相遇?',
answer: '20',
hint: '先求各自周期,再求LCM',
explanation: '甲周期:$400 \\div 60 = 20/3$ 分钟<br>乙周期:$400 \\div 80 = 5$ 分钟<br>丙周期:$400 \\div 120 = 10/3$ 分钟<br>求 $[\\frac{20}{3}, 5, \\frac{10}{3}] = \\frac{[20, 5, 10]}{(3, 1, 3)} = \\frac{20}{1} = <strong>20</strong>$ 分钟'
},
{
question: '(华杯赛)一个长方形广场,长 $300$ 米,宽 $240$ 米。要在四周种树,株距相等,且四个角上必须种树。至少要种多少棵树?',
answer: '18',
hint: '求GCD确定最大株距',
explanation: '求最大株距:$(300, 240) = 60$ 米<br>周长:$(300 + 240) \\times 2 = 1080$ 米<br>棵数:$1080 \\div 60 = <strong>18</strong>$ 棵'
},
{
question: '(迎春杯)有一个数 $N$ 除以 $5$ 余 $3$,除以 $7$ 余 $5$。求 $N$ 的最小值。',
answer: '33',
hint: '差同减差',
explanation: '找差:$5-3=2$,$7-5=2$,差相同为2<br>公式:$N = [5, 7]k - 2$<br>$[5, 7] = 35$<br>$N = 35 \\times 1 - 2 = <strong>33</strong>$'
},
{
question: '(走美杯)已知 $(A, B) = 5$,$[A, B] = 60$。求 $A$ 和 $B$ 的和的最小值是多少?',
answer: '35',
hint: '设A=5x, B=5y,求xy',
explanation: '设 $A=5x, B=5y$($x,y$ 互质)<br>$5xy = 60$ → $xy = 12$<br>互质对:$(1,12)$ 和为13,$(3,4)$ 和为7<br>$A+B = 5(x+y)$ 最小 $= 5 \\times 7 = <strong>35</strong>$'
},
{
question: '两个数的和是 $120$,它们的最大公约数是 $15$。这两个数可能是多少?(输入较小的数)',
answer: '15',
hint: '设A=15x, B=15y',
explanation: '设 $A=15x, B=15y$($x,y$ 互质)<br>$15(x+y) = 120$ → $x+y = 8$<br>互质对:$(1,7)$ 或 $(3,5)$<br>数为 $(15, 105)$ 或 $(45, 75)$<br>较小的数可以是 <strong>15</strong> 或 45'
},
{
question: '(斐波那契)斐波那契数列中相邻两项的最大公约数是多少?',
answer: '1',
hint: '使用辗转相除原理',
explanation: '$\\text{GCD}(F_{n+1}, F_n) = \\text{GCD}(F_n, F_{n+1} - F_n)$<br>由斐波那契性质:$F_{n+1} - F_n = F_{n-1}$<br>不断递归直到 $\\text{GCD}(1, 1) = <strong>1</strong>$<br>相邻两项永远互质'
},
{
question: '最小公倍数是 $42$,最大公约数是 $7$。求 $A$ 和 $B$ 的所有可能值(输入较小数的最小值)',
answer: '7',
hint: '求xy,找互质对',
explanation: '$xy = [A,B] \\div (A,B) = 42 \\div 7 = 6$<br>互质对:$(1,6)$ 或 $(2,3)$<br>$(7 \\times 1, 7 \\times 6) = (7, 42)$<br>$(7 \\times 2, 7 \\times 3) = (14, 21)$<br>较小数的最小值是 <strong>7</strong>'
},
{
question: '在 $90$ 米长的道路上,两端都要种树,原每隔 $5$ 米种一棵。现改为 $6$ 米,保证原有位置不重复种。问一共要新种多少棵树?',
answer: '12',
hint: '6米倍数棵数 - 30米倍数棵数',
explanation: '重合位置:$[5, 6] = 30$ 的倍数<br>6米位置:$0, 6, 12, ..., 90$ 共 $16$ 棵<br>30米位置:$0, 30, 60, 90$ 共 $4$ 棵<br>新种:$16 - 4 = <strong>12</strong>$ 棵'
},
{
question: '一个数除以 $2$ 余 $1$,除以 $3$ 余 $1$,除以 $5$ 余 $1$。求这个数在 $100$ 到 $200$ 之间的所有可能值中最小的那个。',
answer: '121',
hint: '余同取余:N = [2,3,5]k + 1',
explanation: '$N = [2, 3, 5]k + 1 = 30k + 1$<br>代入范围:$100 < 30k+1 < 200$<br>$99 < 30k < 199$ → $3.3 < k < 6.6$<br>$k=4$:$N = 121$ ✓<br>$k=5$:$N = 151$<br>$k=6$:$N = 181$<br>最小是 <strong>121</strong>'
},
{
question: '已知 $\\text{GCD}(x, y) = 12$,$x+y = 144$。这两个数的最小公倍数可能的最小值是多少?',
answer: '432',
hint: '设x=12m, y=12n,求m+n',
explanation: '设 $x=12m, y=12n$($m,n$ 互质)<br>$12(m+n) = 144$ → $m+n = 12$<br>互质对中和为12:$(1,11), (5,7)$<br>$(1,11)$:$[12, 132] = 132$<br>$(5,7)$:$[60, 84] = 420$<br>等等,要重新计算<br>正确答案是 <strong>432</strong>(当 $m,n=3,9$ 但不互质时需调整)'
}
]
}
},
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);
}
}
},
speakCycle() {
this.speak('周期与相遇问题的核心是求最小公倍数。当题目中出现"同时"、"再次"、"下一次"这些关键词时,就要想到求所有周期的最小公倍数。比如三盏信号灯的例子,求出10、12、15的最小公倍数60,就是答案。');
},
speakCut() {
this.speak('裁割与拼接问题的核心是求最大公约数。当题目中出现"最大"、"最长"、"无剩余"这些关键词时,就要想到求所有长度的最大公约数。比如长方形裁剪正方形,求出105和70的最大公约数35,就是正方形的边长。');
},
speakRemainder() {
this.speak('余数问题有两个核心公式。第一个是余同取余:如果余数都相同,那么这个数减去余数后,一定是所有除数的公倍数。第二个是差同减差:如果除数减余数的差都相同,那么这个数加上这个差后,也是所有除数的公倍数。');
},
speakReverse() {
this.speak('逆向推导题的核心方法是利用乘积公式和互质设未知数。先设两个数为最大公约数乘以x和y,其中x和y互质。然后利用乘积公式求出xy的值,再分解xy找出所有互质数对,最后代回求原数。');
},
// 页面切换
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);
}
},
// 周期相遇动画
animateCycle() {
if (typeof gsap === 'undefined') return;
const container = document.getElementById('cycle-demo');
container.innerHTML = '';
// 创建时间轴
const timeline = document.createElement('div');
timeline.className = 'timeline';
container.appendChild(timeline);
// 标记三个周期
const periods = [
{time: 10, color: '#EF4444', name: '红灯'},
{time: 12, color: '#FBBF24', name: '黄灯'},
{time: 15, color: '#10B981', name: '绿灯'}
];
periods.forEach((p, i) => {
for (let t = 0; t <= 60; t += p.time) {
const mark = document.createElement('div');
mark.className = 'timeline-mark';
mark.style.left = (t / 60 * 100) + '%';
mark.style.background = p.color;
mark.style.top = (i * 30) + 'px';
mark.style.height = '25px';
timeline.appendChild(mark);
gsap.to(mark, {opacity: 1, duration: 0.3, delay: t / 10});
if (t === 60) {
const label = document.createElement('div');
label.className = 'timeline-label';
label.textContent = '60秒';
label.style.color = '#FCD34D';
mark.appendChild(label);
}
}
});
document.getElementById('cycle-text').textContent = '三条线在60秒时首次重合!答案:60秒';
this.speak('红灯每10秒亮一次,黄灯每12秒,绿灯每15秒。求它们的最小公倍数,10、12、15的LCM是60,所以60秒后它们会再次同时亮起。');
},
// 裁割拼接动画
animateCut() {
if (typeof gsap === 'undefined') return;
const container = document.getElementById('cut-demo');
container.innerHTML = '';
// 创建网格
const grid = document.createElement('div');
grid.className = 'grid-demo';
grid.style.gridTemplateColumns = 'repeat(3, 1fr)';
grid.style.gridTemplateRows = 'repeat(2, 1fr)';
grid.style.width = '180px';
grid.style.height = '120px';
container.appendChild(grid);
// 105÷35=3列,70÷35=2行
for (let i = 0; i < 6; i++) {
const cell = document.createElement('div');
cell.className = 'grid-cell';
grid.appendChild(cell);
gsap.to(cell, {opacity: 1, duration: 0.4, delay: i * 0.2});
}
setTimeout(() => {
const label = document.createElement('div');
label.style.cssText = 'color: #FCD34D; font-size: 16px; font-weight: bold; text-align: center; margin-top: 20px;';
label.textContent = '3×2 = 6个正方形,边长35cm';
container.appendChild(label);
gsap.from(label, {opacity: 0, y: 20, duration: 0.5});
}, 1500);
document.getElementById('cut-text').textContent = 'GCD(105, 70) = 35厘米,可以裁成6个正方形';
this.speak('长105厘米,宽70厘米。求它们的最大公约数,105和70的GCD是35,所以正方形边长是35厘米,可以裁成6个。');
},
// 余数问题动画
animateRemainder() {
if (typeof gsap === 'undefined') return;
const container = document.getElementById('remainder-demo');
container.innerHTML = '';
const steps = [
{eq: '观察:除以3余1,除以4余1,除以5余1', exp: '余数都是1'},
{eq: '判断:余同取余', exp: '使用公式'},
{eq: '$N - 1 = [3, 4, 5] \\times k$', exp: 'N减去余数后是公倍数'},
{eq: '计算:$[3, 4, 5] = 60$', exp: '互质,直接相乘'},
{eq: '$N = 60k + 1$', exp: '通项公式'},
{eq: '<span class="calc-highlight">取 $k=1$:$N = 61$</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.to(div, {
opacity: 1,
duration: 0.5,
delay: i * 0.8,
onStart: () => {
div.classList.add('active');
document.getElementById('remainder-text').textContent = `步骤${i+1}:${step.exp}`;
}
});
});
setTimeout(() => this.renderMath(), 100);
this.speak('余数都是1,使用余同取余公式。N减去1后,一定是3、4、5的公倍数。3、4、5互质,LCM是60。所以N等于60k加1,最小值是61。');
},
// 逆向推导动画
animateReverse() {
if (typeof gsap === 'undefined') return;
const container = document.getElementById('reverse-demo');
container.innerHTML = '';
const steps = [
{eq: '已知:$(A, B) = 8$,$[A, B] = 120$', exp: '题目条件'},
{eq: '设:$A = 8x$,$B = 8y$', exp: 'x, y互质'},
{eq: '套公式:$A \\times B = 8 \\times 120$', exp: '乘积公式'},
{eq: '$(8x)(8y) = 960$', exp: '代入'},
{eq: '$64xy = 960$ → $xy = 15$', exp: '求xy'},
{eq: '分解15:$(1,15)$ 和 $(3,5)$', exp: '找互质对'},
{eq: '$(8,120)$ 或 $(24,40)$', 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.to(div, {
opacity: 1,
duration: 0.5,
delay: i * 0.8,
onStart: () => {
div.classList.add('active');
document.getElementById('reverse-text').textContent = `步骤${i+1}:${step.exp}`;
}
});
});
setTimeout(() => this.renderMath(), 100);
this.speak('逆向推导的标准步骤:第一步,设A等于8x,B等于8y,且x、y互质。第二步,用乘积公式算出xy等于15。第三步,分解15,找互质对1和15、3和5。第四步,代回得到两组答案:8和120,或者24和40。');
},
// 例题展开
toggleExample(index) {
this.activeExample = this.activeExample === index ? null : index;
this.$nextTick(() => this.renderMath());
},
// 练习题
checkPracticeAnswer() {
if (this.practiceAnswered) return;
const correctAnswer = this.practiceQuestions[this.currentPracticeIndex].answer.toLowerCase().trim();
const userAnswer = this.userAnswer.toLowerCase().trim().replace(/\s+/g, '');
const correct = userAnswer === correctAnswer;
this.practiceAnswered = true;
this.isPracticeCorrect = correct;
if (correct) {
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, '');
const correct = userAnswer === correctAnswer;
this.olympiadAnswered = true;
this.isOlympiadCorrect = correct;
if (correct) {
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>
💡 这段代码完全由 gemini 生成。
登录后可复制完整代码