AT_future_contest_2019_final_b ビジュアライザ

题目描述

[problemUrl]: https://atcoder.jp/contests/future-contest-2019-final/tasks/future_contest_2019_final_b

输入格式

输出格式

说明/提示

### 测试用例生成 我们提供了指定随机种子并在本地生成测试用例的功能。 - 本功能假定在 Chrome 浏览器上运行。无法保证在其他环境下能正常工作,尤其是在 IE 上已确认无法运行。 - 本功能不保证与本次竞赛中的测试用例完全一致。特别是随机数生成的实现可能存在差异,请提前知晓。 - 种子 = ### 可视化工具 我们提供了一个可视化工具,可以根据输入文件和输出文件计算分数并可视化结果。 - 本可视化工具假定在 Chrome 浏览器上运行。无法保证在其他环境下能正常工作,尤其是在 IE 上已确认无法运行。 - 本可视化工具无法提交解答。请在 AtCoder A 问题“モンスターテイマー”页面提交解答。 - 本可视化工具计算的分数不保证与竞赛中的分数一致。因使用本可视化工具造成的任何损失,恕不负责,请提前知晓。 输入文件: 输出文件: ▶ 播放速度:慢快 回合 たかはしくん 正在渴望成为你的伙伴! 分数 0 金钱 0 技能 ※显示的怪兽形象仅为示意,对分数无影响。 const MAX_LEVEL = 10; const APPANAGE = 1000; const COST_TRAINING = 10000; var inputFlg = false; var loadedFlg = false; var T = 1000; var N = 10; var M = 30000; var rendTurn = 0; var tasks = []; var outputData = []; var order = []; var golds = []; var skills = []; var trainings = []; var done = [] var mosterType = [] var invalidQuests = [] var doneQuests = [] class Task{ constructor(inputStr){ this.start = Number(inputStr[0]); this.end = Number(inputStr[1]); this.gold = Number(inputStr[2]); this.takes = [...Array(N)].map(() => 0); for(var i=0; i < N; i++){ this.takes[i] = Number(inputStr[3 + i]); } this.done = false; } output(){ ret = start + "-" + end + " \\" + gold + " \[" + takes[0]; for(var i; i < N; i++){ ret += +","+takes[i]; } ret += "\]" return ret; } } class Order{ constructor(inputStr){ this.type = Number(inputStr[0]); if(this.type == 1 || this.type == 2){ this.param = Number(inputStr[1]); } } output(){ ret = this.type; if(type == 1 || type == 2){ ret += "-" + this.param; } return ret; } } // 测试用例生成 $("#createTestCase").click(function() { let seed = $('#testCaseSeed').val(); if (!isFinite(seed) || Number(seed) < 0 || !seed){ seed = 0; $('#testCaseSeed').val(seed); } console.log("seed="+seed); const random = new Random(seed); records = "1000 10 30000\r\n"; var quests = []; var questType = [0,1,2]; var L = 0; for (var i = 0; i < 30000; i++) { switch(questType[random.nextInt(0, 2)]){ case 0: L = random.nextInt(2, 10); break; case 1: L = random.nextInt(11, 100); break; case 2: L = random.nextInt(101, 1000); break; default: console.log("Error!"); return; } var A = random.nextInt(1, Math.max(1,1000 - L)); var B = A + L - 1; var takes = [...Array(10)].map(() => 0); takes[0] = random.nextInt(1, 10); for(var j = 1; j < 10; j++){ takes[j] = random.nextInt(0, takes[j-1]); } // 洗牌 for(var j = 10 - 1; j > 0; j--){ var r = Math.floor(random.nextDouble() * (j + 1)); var tmp = takes[j]; takes[j] = takes[r]; takes[r] = tmp; } var sum = takes.reduce((a,x) => a+=x,0); var C = Math.floor(sum * 1.3 * random.nextInt(1,2000 )); records += A + " " + B + " " + C; for(var j = 0; j < 10; j++){ records += " " + takes[j]; } records += "\r\n"; } var blob = new Blob([records], { "type": "text/plain" }); window.URL = window.webkitURL || window.URL; $("#download").attr("href", window.URL.createObjectURL(blob)); document.getElementById('download').innerText = "Input_" + seed; let fileName = "testCase_" + seed + ".txt"; $('#download').attr('download', fileName); }); class Random { constructor(seed = 88675123){ this.x = 123456789; this.y = 362436069; this.z = 521288629; this.w = seed; } // XorShift next() { let t; t = this.x ^ (this.x >> 19)) ^ (t ^ (t >>> 8)); } nextInt(min, max) { const r = Math.abs(this.next()); return min + (r % (max + 1 - min)); } nextDouble() { const r = Math.abs(this.next()); return (r % (1000000007 + 1)) / 1000000007; } }; // 输入文件读取 var handleInputFiles = function (file, callback) { document.getElementById('inputFile').innerText = ''; document.getElementById('outputFile').innerText = ''; $('#output').val(''); inputFlg = false; loadedFlg = false; document.getElementById('score').innerText = 0; var reader = new FileReader(); reader.readAsText(file[0]); reader.onload = function (ev) { const inputDatalist = reader.result.split(/\r\n|\r|\n/); if(inputDatalist.length < 1){ console.log("No Text Error!! " + inputDatalist.length); document.getElementById('inputFile').innerText = 'error!'; $('#input').val(''); return; } var firstLine = inputDatalist[0].split(" "); if(firstLine.length != 3){ console.log("First Line Error!! " + inputDatalist.length); document.getElementById('inputFile').innerText = 'error!'; $('#input').val(''); return; } for(var i = 0; i < 3; i++){ if(Number.isNaN(Number(firstLine[i]))){ console.log("First Line Error!! " + inputDatalist.length); document.getElementById('inputFile').innerText = 'error!'; $('#input').val(''); return; } } T = Number(firstLine[0]); N = Number(firstLine[1]); M = Number(firstLine[2]); tasks = [...Array(M)].map(() => null); if(inputDatalist.length < M){ console.log("T Error!! " + inputDatalist.length); document.getElementById('inputFile').innerText = 'error! short line!'; $('#input').val(''); return; } for (var i = 0; i < M; i++) { line = inputDatalist[i+1].split(" "); if(line.length < 3 + N){ console.log("M error!! " + (i+1) + " " +inputDatalist[i].length); console.log(inputDatalist[i]); document.getElementById('inputFile').innerText = 'error! invalid task!'; $('#input').val(''); return; } for (var j = 0; j < 3 + N; j++) { if(Number.isNaN(Number(line[j]))){ document.getElementById('inputFile').innerText = 'error! not number!'; console.log("type error!! Line=" + i); $('#input').val(''); return; } if(Number(line[j]) < 0){ document.getElementById('inputFile').innerText = 'error! negative value!'; console.log("negative value error!! Line=" + i); $('#input').val(''); return; } if(j < 3){ continue; } if(Number(line[j]) > MAX_LEVEL){ document.getElementById('inputFile').innerText = 'error! over level 10!'; console.log("over level error!! Line=" + i); $('#input').val(''); return; } } tasks[i] = new Task(line); } document.getElementById('inputFile').innerText = 'OK!'; console.log("input OK!"); inputFlg = true; setTimeout(function() { callback(-1); }, 50); }; } function clearInFilePath() { $('#input').val(''); } function clearOutFilePath() { $('#output').val(''); } // 输出文件读取 function handleOutputFiles(file, callback) { document.getElementById('outputFile').innerText = ''; if (!inputFlg) { document.getElementById('outputFile').innerText = 'input first!'; $('#output').val(''); return; } loadedFlg = false; outputData = []; document.getElementById('score').innerText = 0; var reader = new FileReader(); reader.readAsText(file[0]); reader.onload = function (ev) { const outputDatalist = reader.result.split(/\r\n|\r|\n/); if(outputDatalist.length < T){ console.log("output filr error!"); document.getElementById('outputFile').innerText = 'error! short line!'; $('#output').val(''); return; } order = [...Array(T)].map(() => null); for (var i = 0; i < T; i++) { line = outputDatalist[i].split(" "); if(Number.isNaN(Number(line[0]))){ console.log("output filr error! Line=" + i); console.log(row); document.getElementById('outputFile').innerText = 'error! not number!'; $('#output').val(''); return; } switch(Number(line[0])){ case 1: if(line.lengh < 2){ console.log("output filr error! Line=" + i); document.getElementById('outputFile').innerText = 'error! needs second param!'; $('#output').val(''); return; } if(Number.isNaN(Number(line[1]))){ console.log("output filr error! Line=" + i); console.log(row); document.getElementById('outputFile').innerText = 'error! not number!'; $('#output').val(''); return; } if(Number(line[1]) > MAX_LEVEL || Number(line[1]) < 1){ console.log("output filr error! Line=" + i); document.getElementById('outputFile').innerText = 'error! invalid skill no!'; $('#output').val(''); return; } order[i] = new Order(line); break; case 2: if(line.lengh < 2){ console.log("output filr error! Line=" + i); document.getElementById('outputFile').innerText = 'error! needs second param!'; $('#output').val(''); return; } if(Number.isNaN(Number(line[1]))){ console.log("output filr error! Line=" + i); console.log(row); document.getElementById('outputFile').innerText = 'error! not number!'; $('#output').val(''); return; } if(Number(line[1]) > M || Number(line[1]) < 1){ console.log("output filr error! Line=" + i); document.getElementById('outputFile').innerText = 'error! invalid task no!'; $('#output').val(''); return; } order[i] = new Order(line); break; case 3: order[i] = new Order(line); break; default: document.getElementById('outputFile').innerText = 'error! not 1 or 2 or 3!'; console.log("output filr error! Line=" + i); console.log("error!!"); $('#output').val(''); return; } } document.getElementById('outputFile').innerText = 'OK!'; console.log("output OK!"); loadedFlg = true; setTimeout(function() { simulate(); callback(T+1); }, 50); }; } function simulate() { if(!inputFlg || ! loadedFlg){ return; } // 初始化 done = [...Array(M)].map(() => false); skills = [...Array(T+1)].map(() => [...Array(N)].map(() => 0)); trainings = [...Array(T+1)].map(() => [...Array(N)].map(() => 0)); golds = [...Array(T+1)].map(() => 0); golds[0] = 1000; mosterType = [...Array(T+1)].map(() => "m1"); invalidQuests = [...Array(T+1)].map(() => false); doneQuests = [...Array(T+1)].map(() => false); for (var i = 0; i < T; i++) { // 复制 for(var j = 0; j < N; j++) { skills[i+1][j] = skills[i][j]; trainings[i+1][j] = trainings[i][j]; } mosterType[i+1] = mosterType[i]; var nowGold = golds[i]; var nowOrder = order[i]; switch(nowOrder.type){ case 1: var skillNo = nowOrder.param-1; if(skills[i][skillNo] >= MAX_LEVEL){ break; } var nextLevel = skills[i][skillNo] + 1; if(nowGold < Math.pow(2,nextLevel) * COST_TRAINING){ break; } nowGold -= Math.pow(2,nextLevel) * COST_TRAINING; trainings[i+1][skillNo]++; if(trainings[i+1][skillNo] >= nextLevel){ trainings[i+1][skillNo]=0; skills[i+1][skillNo]++; var sum = 0; for(var j = 0; j < N; j++) { sum += skills[i+1][j]; } switch(sum){ case 10: mosterType[i+1] = "m2-a" for(var j = 0; j < N; j++) { if(skills[i+1][j]>1){ mosterType[i+1] = "m2-b" break; } } break; case 20: mosterType[i+1] = "m3-a" for(var j = 0; j < N; j++) { if(skills[i+1][j]>2){ mosterType[i+1] = "m3-b" break; } } break; case 30: mosterType[i+1] = "m4-a" for(var j = 0; j < N; j++) { if(skills[i+1][j]>3){ mosterType[i+1] = "m4-b" break; } } break; case 50: mosterType[i+1] = "m5-a" for(var j = 0; j < N; j++) { if(skills[i+1][j]>5){ mosterType[i+1] = "m5-b" break; } } break; case 70: mosterType[i+1] = "m6-a" for(var j = 0; j < N; j++) { if(skills[i+1][j]>7){ mosterType[i+1] = "m6-b" break; } } break; case 90: mosterType[i+1] = "m7-a" for(var j = 0; j < N; j++) { if(skills[i+1][j]>9){ mosterType[i+1] = "m7-b" break; } } break; case 100: mosterType[i+1] = "m8" break; default: break; } } break; case 2: var task = tasks[nowOrder.param-1]; if(task.start > i+1 || task.end < i+1){ invalidQuests[i] = true; break; } if(done[nowOrder.param-1]){ doneQuests[i] = true; break; } money = task.gold; money *= (1 + 9 * (i+1 - task.start) / (task.end - task.start)); skillLack = 0; for (var j = 0; j < N; j++){ skillLack += Math.max(0, task.takes[j] - skills[i][j]); } if (skillLack == 0){ money *= 10; } else { money *= Math.pow(0.5, skillLack); money += 1e-9; } nowGold += Math.floor(money); done[nowOrder.param-1] = true; break; case 3: nowGold += APPANAGE; break; default: document.getElementById('outputFile').innerText = 'error! not 1 or 2 or 3!'; console.log("output filr error! Line=" + i); console.log("error!!"); $('#output').val(''); return; } golds[i + 1] = nowGold; var str = i + " " + nowGold + " ["; for(var j = 0; j < N; j++){ str += skills[i+1][j] + ","; } str += "]"; //console.log(str); } document.getElementById('score').innerText = golds[T]; } function wrongAnswer(str, t) { console.log("simulate error!! turn="+ t + " " + str); outputData = []; _isRunning = false; start.innerText = '▶'; render(t); document.getElementById('slider1o').value = t; document.getElementById('outputFile').innerText = 'error!'; document.getElementById('score').innerText = 'WA'; } var render = function(rendTurn) { this.rendTurn = rendTurn; if(!inputFlg){ return; } if(rendTurn < 0){ document.getElementById('money').innerText = 0; return; } if(!loadedFlg){ return; } if(rendTurn >= T){ document.getElementById('money').innerText = golds[T]; document.getElementById('message-area').innerHTML = "你获得了"+golds[T]+ " 日元!"; for(var i = 0;i < N;i++){ myChart.chart.data.datasets[0].data[i] = skills[T][i]; } myChart.chart.update(); document.getElementById("monster").className = mosterType[T]; return; } document.getElementById('money').innerText = golds[rendTurn]; for(var i=0;i T + 2){ _isRunning = false; start.innerText = '▶'; cancelAnimationFrame(_animationID); output.value = 0; return; } _animationID = requestAnimationFrame(autoUpdate); frame++; if(frame % (50 - Number(animeSpeed.value)) !== 0){ return; } render(Number(output.value)); output.value = tmp; value = tmp; set_value(); } // 开始按钮点击 start.onclick = function(evt){ if (_isRunning) { _isRunning = false; start.innerText = '▶'; cancelAnimationFrame(_animationID); } else if(loadedFlg){ _isRunning = true; start.innerText = '■'; autoUpdate(); } else { if(inputFlg && order.length == T+1){ $('#input').val(''); $('#output').val(''); if(loadedFlg){ _isRunning = true; start.innerText = '■'; autoUpdate(); } } } }; // 点击刻度部分 slider.onclick = function(evt){ dragging = true; document.onmousemove(evt); document.onmouseup(); }; // 数值变更 output.onchange = function(evt){ value = evt.target.value; render(Number(evt.target.value)); }; // 拖拽开始 input.onmousedown = function(evt){ dragging = true; return false; }; // 拖拽结束 document.onmouseup = function(evt){ if (dragging) { dragging = false; output.value = value; render(value); } }; document.onmousemove = function(evt){ if(dragging){ // 拖拽中 if(!evt){ evt = window.event; } var left = evt.clientX; var rect = slider.getBoundingClientRect(); // 根据鼠标坐标和滑块位置决定值 value = Math.round(left - rect.left - width); // 超出滑块范围 if (value < 0) { value = 0; } else if (value > slider.clientWidth) { value = slider.clientWidth; } set_value(); return false; } }; })(); // 颜色设置 var colorSet = { red: 'rgb(255, 99, 132)', orange: 'rgb(255, 159, 64)', yellow: 'rgb(255, 205, 86)', green: 'rgb(75, 192, 192)', blue: 'rgb(54, 162, 235)', purple: 'rgb(153, 102, 255)', grey: 'rgb(201, 203, 207)' }; // 颜色RGB转换 var color = Chart.helpers.color; /* * 图表初始设置 */ var config = { type: 'radar', data: { labels: ["No.1", "No.2", "No.3", "No.4", "No.5", "No.6", "No.7", "No.8", "No.9", "No.10"], datasets: [{ label: "等级", backgroundColor: color(colorSet.blue).alpha(0.5).rgbString(), borderColor: colorSet.blue, pointBackgroundColor: colorSet.blue, data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },] }, options: { chartArea: { backgroundColor: "#000" }, animation: { duration: 1500, }, maintainAspectRatio: false, showTooltips: false, responsive: false, legend: { display: false }, title: { display: false }, scale: { display: true, pointLabels: { fontSize: 10, fontColor: colorSet.yellow }, gridLines: { display: true, color: colorSet.yellow }, ticks: { display: false, fontColor: "#FFF", fontSize: 8, min: 0, max: 10 } } } }; var myChart = new Chart( $("#skill-chart"), config); 由 ChatGPT 4.1 翻译