黑塔转圈圈问题

偶然在知乎看到的,还被诈骗了一下。难度大概洛谷绿?


nnn 名敌人,第 iii 名敌人初始生命值为 aia_iai

黑塔女士的普通攻击可以对一名敌人造成 111 点伤害。此外,黑塔女士的天赋,会在敌人的生命值首次降低到初始值的二分之一(向下取整)时,立即发动追加攻击,对所有敌人造成 111 点伤害。

追加攻击造成的伤害可以继续触发追加攻击,且多个敌人的生命值同时下降到二分之一时,每个敌人都可以触发一次追加攻击。

现在有许多敌人,黑塔女士应该如何用最少的普通攻击消灭所有敌人呢?

保证 1≤n≤105,1≤ai≤1091\leq n\leq 10^5,1\leq a_i\leq 10^91n105,1ai109

加强版:1≤n≤1071\leq n\leq 10^71n107。(不考虑输入时间)


不妨令 bi=⌊ai2⌋b_i=\lfloor\frac{a_i}2\rfloorbi=2aici=ai−bic_i=a_i-b_ici=aibi

考虑如何刻画答案。将所有敌人按生命值首次不大于 bib_ibi 的时刻升序排列,则答案为:

∑i=1nmax⁡(ai−n,ci−(i−1),0)=∑i=1nxi+∑i=1nmax⁡(yi−i,0) \sum_{i=1}^n\max(a_i-n,c_i-(i-1),0)=\sum_{i=1}^nx_i+\sum_{i=1}^n\max(y_i-i,0)i=1nmax(ain,ci(i1),0)=i=1nxi+i=1nmax(yii,0)

其中 xi=max⁡(ai−n,0)x_i=\max(a_i-n,0)xi=max(ain,0)yi=ci−xi+1y_i=c_i-x_i+1yi=cixi+1

很明显,我们按照 yiy_iyi 升序排列最优。

yi<0y_i<0yi<0 的所有值之间的顺序并不重要;yi>ny_i>nyi>n 的所有值之间的顺序并不重要。

可以只对 1≤yi≤n1\leq y_i\leq n1yin 的元素进行桶排。复杂度做到 O(n)O(n)O(n)

代码太简单就不贴了。

from fastapi import FastAPI, HTTPException, Request, WebSocketDisconnect from fastapi.responses import HTMLResponse, JSONResponse from fastapi.staticfiles import StaticFiles import uvicorn from server.generate.user_portrait_generate import * from server.data.sensitiveWord_server import * from server.chat_group.clientManager_server import * from server.ai_api.base.base_feiying_service import * from server.ai_api.base.base_doubao_service import * from typing import AsyncGenerator from contextlib import asynccontextmanager from server.generate.story_generate import * from fastapi.middleware.cors import CORSMiddleware # 在初始化属性之前的函数,用于定时任务的制作 @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: # 在应用启动时执行的代码 # 启动定时生成 HTML 的任务 asyncio.create_task(all_periodic_html_generation()) asyncio.create_task(random_periodic_html_generation()) asyncio.create_task(all_treemap_html_generation()) asyncio.create_task(personality_update_story_generate_day()) # 应用启动后会在这里暂停,等待应用关闭 yield # 函数后面是在应用关闭时执行的代码 # region 基础属性初始化生成 # 客户端管理器 clients_manager = ClientsManager() # 消息存储,使用字典来存储群组的消息 message_store = [] # 全局知识图谱实例 girl_knowledge_graph = MemoryKnowledgeGraph() # 过滤词系统 filter_system = SensitiveWordFilter(serialized_path="sensitive_filter.pkl") # FastAPI # 创建 FastAPI 实例并传入 lifespan app = FastAPI(lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=["*"], # 允许所有来源 allow_credentials=True, allow_methods=["*"], # 允许所有方法 allow_headers=["*"], # 允许所有头 ) # 可信的记忆 cached_memories = set() app.mount("/static", StaticFiles(directory="static"), name="static") app.mount("/memory/using", StaticFiles(directory="memory/using"), name="memory_using") # 获取单独一次的girl_setting system_content = "" # 用于发送给UE的聊天历史 chat_history_to_ue = [] # 语音识别文本模型 audio_to_text_model_path = "model/vosk-model-small-cn-0.22/" # 音频保存位置 audio_save_file_path = "uploads/audio" ai_model_name = "" ai_api_key = "" deepseek_api = "" # 飞影设置 YOUR_TOKEN = "" VOICE_ID = "" AVATAR_ID = "" SHOW_Subtitle = "" num = 0 remember_me_update_state = 0 # 虚拟市民图像保存 virtual_cities_only_save_image_path = 'memory/using/virtual_image.png' # 生成的讲故事视频的链接 remember_me_video_url = "" global_task_id = "" # 豆包的API key dou_bao_api_key = "" app_port = 10808 # 人设记录 current_user_profile = "" # 是否更新 全部 all_video_update_state = 0 # 人设更新系统 # personality_system = None # endregion def begin_init(): global system_content,ai_model_name,ai_api_key, deepseek_api, app_port # 声明使用全局变量 global YOUR_TOKEN, VOICE_ID, AVATAR_ID, SHOW_Subtitle, dou_bao_api_key # 人设加载 file_path = r"memory\GirlSetting.txt" girl_config_path = r"memory\Girl_config.txt" with open(girl_config_path, "r", encoding="utf-8") as f: for line in f: if "AI_MODEL =" in line: ai_model_name = line.split('"')[1] print(f"AI_MODEL: {ai_model_name}") elif "AI_API_KEY =" in line: ai_api_key = line.split('"')[1] print(f"AI_API_KEY: {ai_api_key}") elif "Deepseek_API =" in line: deepseek_api = line.split('"')[1] print(f"Deepseek_API: {deepseek_api}") elif "FeiYing_YOUR_TOKEN =" in line: YOUR_TOKEN = line.split('"')[1] print(f"FeiYing_Token: {YOUR_TOKEN}") elif "FeiYing_VOICE_ID =" in line: VOICE_ID = line.split('"')[1] print(f"FeiYing_Voice ID: {VOICE_ID}") elif "FeiYing_AVATAR_ID =" in line: AVATAR_ID = line.split('"')[1] print(f"Avatar ID: {AVATAR_ID}") elif "FeiYing_SHOW_Subtitle =" in line: SHOW_Subtitle = int(line.split("=")[1].strip()) print(f"FeiYing_SHOW_Subtitle: {SHOW_Subtitle}") elif "DouBao_API_KEY =" in line: dou_bao_api_key = line.split('"')[1] print(f"DouBao_API_KEY: {dou_bao_api_key}") elif "APP_Port =" in line: app_port = int(line.split("=")[1].strip()) print(f"APP_Port: {app_port}") with open(file_path, "r", encoding="utf-8") as file: system_content = file.read().strip() # 知识图谱记忆库加载 girl_knowledge_graph.load_graph("girl_knowledge_graph.graphml") # 初始化 begin_init() # 创建服务实例 service = GirlZhipuAIService(ai_api_key, system_content, ai_model_name) dou_bao_service = BaseDoubaoService(api_key=dou_bao_api_key) # API检测 def check_api_key(api_key: str): if api_key != "88888888": return HTTPException(status_code=401, detail="无效的API密钥") # 请求写法:http://127.0.0.1:8888/chat_without_memory?api_key=88888888 json:{message:xxx} @app.post("/chat_with_memory") async def chat_with_memory(request: Request, api_key: str = ''): check_api_key(api_key) data = await request.json() user_input = data.get("message", "") if not user_input: raise HTTPException(status_code=400, detail="请求内容不能为空") # 使用记忆库 temp_memory = girl_knowledge_graph.search_memory(user_input) retries = 0 max_retries = 3 while retries < max_retries: reply = service.chat_graph_knowledge(user_input, temp_memory, True) # 不修改记忆库 result = girl_knowledge_graph.parse_and_store_response(reply,False) if result: return {"response": result} retries += 1 return {"response": "emmm...我得仔细思考一下你说的问题,因为我现在脑子比较混乱"} @app.post("/chat_without_memory") async def chat_without_memory(request: Request, api_key: str = ''): check_api_key(api_key) data = await request.json() user_input = data.get("message", "") if not user_input: raise HTTPException(status_code=400, detail="请求内容不能为空") # 不使用记忆库 retries = 0 max_retries = 3 while retries < max_retries: # 不使用记忆库 reply = service.chat_graph_knowledge(user_input, "", False,False) result = girl_knowledge_graph.parse_and_store_response(reply,False) if result: return {"response": result} retries += 1 return {"response": "emmm...我得仔细思考一下你说的问题,因为我现在脑子比较混乱"} @app.get("/all_memory", response_class=HTMLResponse) async def show_girl_graph(request: Request): file_path = 'static/All_Girl_Graph.html' if os.path.exists(file_path): # 如果文件存在,读取并返回文件内容 with open(file_path, 'r', encoding='utf-8') as file: content = file.read() return HTMLResponse(content=content) else: return "404" @app.get("/memory", response_class=HTMLResponse) async def show_girl_graph(request: Request): file_path = 'static/Random_Girl_Graph.html' if os.path.exists(file_path): # 如果文件存在,读取并返回文件内容 with open(file_path, 'r', encoding='utf-8') as file: content = file.read() return HTMLResponse(content=content) else: return "404" @app.get("/remember_me_not_save_me/treemap_memory", response_class=HTMLResponse) async def show_girl_graph(request: Request): file_path = 'static/Treemap_Girl_Graph.html' if os.path.exists(file_path): # 如果文件存在,读取并返回文件内容 with open(file_path, 'r', encoding='utf-8') as file: content = file.read() return HTMLResponse(content=content) else: return "404" @app.post("/get_app_history") async def get_app_history(): if chat_history_to_ue: # 获取历史记录 history = chat_history_to_ue.copy() # 清空历史记录 chat_history_to_ue.clear() return history else: return "" @app.post("/get_credible_memory") async def get_credible_memory(request: Request): # Unreal 的残留用代码 global cached_memories data = await request.body() temp_data = data.decode("utf-8") print(temp_data) # 从知识图谱中获取“认为可信的记忆” new_memories = girl_knowledge_graph.get_memories_connections("认为可信的记忆") # 转换为集合以便处理 new_memories_set = set(new_memories.split("|")) if temp_data == "First": print("First") if not new_memories_set: return "" return "|".join(new_memories_set) else: print("NoFirst") # 计算新增的记忆 unique_memories = new_memories_set - cached_memories # 更新已缓存的记忆 cached_memories.update(unique_memories) if not unique_memories: return "" return "|".join(unique_memories) @app.post("/remember_me_not_save_me/get_user_portrait") async def get_user_portrait(): base_profile_path = "memory/using/user_portrait.txt" with open(base_profile_path, "r", encoding="utf-8") as f: content= f.read() print(content) return content @app.get("/remember_me_not_save_me/get_video_update_state") async def get_video_update_state(): global remember_me_update_state,YOUR_TOKEN,global_task_id,remember_me_video_url, all_video_update_state video_url = check_video_status(YOUR_TOKEN, global_task_id) if video_url in ["1", "2", "4"]: return JSONResponse({ "update": all_video_update_state, "generate": 0 }) else: remember_me_video_url = video_url remember_me_update_state = 1 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") record = f"{timestamp}:{video_url}\n" # 追加写入到文件(如果文件不存在会自动创建) with open("memory/video_link_records.txt", "a", encoding="utf-8") as file: file.write(record) return JSONResponse({ "update": all_video_update_state, "generate": remember_me_update_state }) @app.get("/remember_me_not_save_me/get_video_link") async def get_video_url(): global remember_me_video_url,remember_me_update_state, all_video_update_state remember_me_update_state = 0 all_video_update_state = 0 return remember_me_video_url @app.websocket("/connect_server") async def websocket_endpoint(websocket: WebSocket): # 接受 WebSocket 连接 await websocket.accept() # 记录客户端连接 await clients_manager.connect(websocket) try: while True: # 等待客户端发送消息 message = await websocket.receive_text() # 判断消息类型:如果是 Base64 编码的图片 if message.startswith("IMAGE_MESSAGE:"): # 处理 Base64 图片 image_data = message[len("IMAGE_MESSAGE:"):].strip() image_path = await save_image_from_base64(image_data) # 将保存的图片路径广播给其他客户端 await clients_manager.broadcast(f"Image received: {image_path}", sender=websocket, all_return=False) append_to_log("User", image_path) asyncio.create_task(add_memory_image(image_path)) elif message.startswith("USER_MESSAGE:"): # 广播消息给除了自己以外的所有客户端 user_message = message[len("USER_MESSAGE:"):].strip() user_message = filter_system.process_text(user_message) await clients_manager.broadcast(user_message, sender=websocket, all_return=False) message_store.append({"message": user_message, "sender": "user"}) # 写入本地 append_to_log("User", user_message) asyncio.create_task(add_memory_str(user_message)) else: append_to_log("System", "Unknown message type received") # 启动一个定时任务来检查消息是否已经超过 5 秒 asyncio.create_task(check_message_timeout()) except WebSocketDisconnect: # 如果客户端断开连接,则从管理器中删除该连接 await clients_manager.disconnect(websocket) async def all_periodic_html_generation(): while True: # 生成 HTML girl_knowledge_graph.generate_graph_dynamic_html('static/All_Girl_Graph.html') # 去重 - 0.8 girl_knowledge_graph.remove_similar_nodes_distance(0.8) # 每60秒执行一次 await asyncio.sleep(300) async def random_periodic_html_generation(): while True: # 生成 HTML girl_knowledge_graph.random_Generate_dynamic_html('static/Random_Girl_Graph.html') # 每20秒执行一次 await asyncio.sleep(20) async def all_treemap_html_generation(): while True: # 生成 HTML result = girl_knowledge_graph.get_recent_memories(days=500) categorized = girl_knowledge_graph.categorize_memories_by_type(result) girl_knowledge_graph.generate_fullscreen_treemap_html(categorized, 'static/Treemap_Girl_Graph.html') # 每10分钟执行一次 await asyncio.sleep(600) async def personality_update_story_generate_day(): # 一整个更新视频流程 global virtual_cities_only_save_image_path, num, current_user_profile, all_video_update_state global YOUR_TOKEN, VOICE_ID, AVATAR_ID, SHOW_Subtitle global global_task_id, deepseek_api if num !=0: # 更新人设 current_girl_system_content = service.system_girl # 记录历史 --> 用于回滚过去人设 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") save_file_path = f"memory/personality_history/GirlSetting_{timestamp}.txt" os.makedirs(os.path.dirname(save_file_path), exist_ok=True) write_to_txt(save_file_path,current_girl_system_content) # 生成新的人设 并 修改 recent_memory = girl_knowledge_graph.get_recent_memories(days=1) new_setting = service.chat_update_girl_setting(current_girl_system_content,recent_memory) write_to_txt("memory/GirlSetting.txt",new_setting) service.system_girl = new_setting print("新人设生成修改完毕") # 基于新的记忆生成新的用户画像-->"memory/using/user_portrait.txt" new_profile = merge_profiles_with_deepseek(service=service, deepseek_api=deepseek_api, days=0.5, log_path="log.txt", new_setting=new_setting, recent_user_profile=current_user_profile) current_user_profile = new_profile # 生成新的画图提示词 image_prompt = "基于这个用户画像与人设去生成一个专门用于绘画的json提示词,画一个大家心目中的人物,正面人脸,这个是用户画像,超写实:" + new_profile + "\n人设:" + new_setting user_portrait_prompt = service.chat(image_prompt) # 画图提示词-->生成图 """ # chatglm画图 image_url = service.generate_image( prompt=user_portrait_prompt, model="cogview-3-flash", size="1024x1024", watermark_enabled=False # 去水印 )""" image_url = dou_bao_service.generate_image_and_get_url( prompt=user_portrait_prompt, watermark=False ) # 目录存在 os.makedirs("memory/virtual_image", exist_ok=True) # 保存位置 image_timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") time_save_path = f'memory/virtual_image/VI_{image_timestamp}.png' response = requests.get(image_url, stream=True) # 下载 + 保存图片 image_data = b"" for chunk in response.iter_content(chunk_size=8192): image_data += chunk with open(virtual_cities_only_save_image_path, 'wb') as file: file.write(image_data) # 保存到带时间戳的路径(历史记录) with open(time_save_path, 'wb') as file: file.write(image_data) # 故事生成 -> "memory/using/merged_stories.txt" final_merged_story = await merge_stories_with_deepseek(deepseek_api=deepseek_api, service=service,open_log_path="log.txt", knowledge_graph=girl_knowledge_graph, recent_user_profile= current_user_profile) # 将图片转为视频 # generate_video_from_image(used_image_path, "static/video/loop_video.mp4", 5) # 创建视频生成任务 text_prompt = "电影感特写镜头,固定机位。人物凝视镜头,缓慢地眨一次眼,随后做一个微小的自然动作(例如:嘴角浅笑),然后恢复初始的平静表情。动态微妙,镜头稳定,风格化画面,无缝循环。" # 虚拟形象图片 image_url = "http://150.158.170.63:" + str(app_port) + "/" + virtual_cities_only_save_image_path video_task = dou_bao_service.create_video_generation_task( text_prompt=text_prompt, image_url=image_url, watermark=False ) task_id = video_task.get("id") if task_id: # 等待任务完成 video_url, status = dou_bao_service.wait_for_video_task(task_id) if status == "succeeded": print("视频生成成功,URL:", video_url) timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") video_record = f"{timestamp}:{video_url}" os.makedirs(os.path.dirname(save_file_path), exist_ok=True) with open("memory/dou_bao_no_voice_video.txt", "a", encoding="utf-8") as file: file.write(video_record) # 下载并覆盖视频 await dou_bao_service.download_file(video_url, "static/video/loop_video.mp4") # 上传飞影视频 avatar_id = create_avatar_from_local_video_back_avatar_id(token=YOUR_TOKEN, video_path="static/video/loop_video.mp4", title="test") timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") record = f"{timestamp}:{avatar_id}\n" # 追加写入到文件(如果文件不存在会自动创建) with open("memory/avatar_id_records.txt", "a", encoding="utf-8") as file: file.write(record) result = create_feiying_video_by_tts( token=YOUR_TOKEN, voice_id=VOICE_ID, avatar_id=avatar_id, text=final_merged_story, show_subtitle=SHOW_Subtitle ) global_task_id = result.get("task_id") timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") record = f"{timestamp}:https://hfw-api.hifly.cc/api/v2/hifly/video/task?task_id={global_task_id}\n" # 追加写入到文件(如果文件不存在会自动创建) with open("memory/video_task_records.txt", "a", encoding="utf-8") as file: file.write(record) all_video_update_state = 1 elif num == 0: num = 1 # 每1个小时生成一次新的人设表、故事、用户画像、飞影视频 await asyncio.sleep(3600) # 定时检查是否有新的消息,如果没有消息,则调用 AI 生成回复 async def check_message_timeout(): # 等待 5 秒钟 await asyncio.sleep(5) # 检查当前消息列表 if len(message_store) > 0: # 随机选择一条消息 selected_message = random.choice(message_store) question = selected_message["message"] # 调用 AI 获取回复 ai_response = await ai_chat(question) append_to_log("AI", ai_response) # 广播消息给所有客户端 await clients_manager.broadcast(ai_response, sender="ai", all_return=True) chat_history_to_ue.append({"question": question, "answer": ai_response}) # 清空消息存储 message_store.clear() async def ai_chat(player_message: str): # 检索回忆 temp_memory = girl_knowledge_graph.search_memory(player_message) retries = 0 max_retries = 3 while retries < max_retries: # 请求聊天生成的回答 reply = service.chat_graph_knowledge(player_message, temp_memory, True) # 解析并存储响应 result = girl_knowledge_graph.parse_and_store_response(reply) if result: # 如果解析成功,返回结果 return result else: retries += 1 if retries>= max_retries: return """emmm...我得仔细思考一下你说的问题,因为我现在脑子比较混乱""" async def add_memory_str(new_memory: str): memory_text = service.chat_graph_knowledge(new_memory, "", False) girl_knowledge_graph.parse_and_store_response(memory_text) async def add_memory_image(file_path: str): res = service.chat_image_solve(file_path) answer = """这个是别人给你发来照片后,你自己对照片的描述:""" + res + """\n请你根据人设和相关回忆设定回答""" message_store.append({"message": answer, "sender": "user"}) # 存入记忆 memory_text = service.chat_graph_knowledge(res, "", False) girl_knowledge_graph.parse_and_store_response(memory_text) async def audio_get(): wav_path = await asyncio.to_thread(record_audio_manual_stop, "output/audio_files") return wav_path async def audio_to_text(audio_file_path: str): audio_text = transcribe_audio(audio_to_text_model_path,audio_file_path=audio_file_path) return audio_text if __name__ == '__main__': # a = asyncio.run(audio_to_text("C:\\Users\\ADMIN\\Desktop\\声音\\小黑塔\\小黑塔的初次见面语音.wav")) # print(a) # merge_stories_with_deepseek() # 用于自己使用 # asyncio.run(personality_update_story_generate_day()) # 人设重新设置和故事生成 uvicorn.run(app, host='0.0.0.0', port=app_port, log_level="info") # asyncio.run(t_2()) 打包后的python文件,打开报错: Error in sys.excepthook: Original exception was: Error in sys.excepthook! Original exception was:
10-09
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值