直接运行即可,会将分析输出至 stderr。
字符串格式化库来自 Github,非常感谢。
英语有点差,欢迎捉虫
里面的 round end 代表行动结束,round finish 代表回合结束
增益那些都是立刻加到数值上,到增益结束再减回来
/******************************
- @GavinCQTD / 2025-07-02 16:53:25
- "P7610 [THUPC 2021] 群星连结" From Luogu
- # https://www.luogu.com.cn/problem/P7610
******************************/
// #define NDEBUG
#include <algorithm>
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <vector>
// #START - format.h
/*
From https://github.com/arajar/format
*/
#include <string>
#include <vector>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <iomanip>
namespace util
{
class ArgBase
{
public:
ArgBase() {}
virtual ~ArgBase() {}
virtual void Format(std::ostringstream &ss, const std::string& fmt) = 0;
};
template <class T>
class Arg : public ArgBase
{
public:
Arg(T arg) : m_arg(arg) {}
virtual ~Arg(){}
virtual void Format(std::ostringstream &ss, const std::string& fmt)
{
ss << m_arg;
}
private:
T m_arg;
};
class ArgArray : public std::vector < ArgBase* >
{
public:
ArgArray() {}
~ArgArray()
{
std::for_each(begin(), end(), [](ArgBase* p){ delete p; });
}
};
static void FormatItem(std::ostringstream& ss, const std::string& item, const ArgArray& args)
{
int index = 0;
int alignment = 0;
std::string fmt;
char* endptr = nullptr;
index = strtol(&item[0], &endptr, 10);
if (index < 0 || index >= (int)args.size())
{
return;
}
if (*endptr == ',')
{
alignment = strtol(endptr + 1, &endptr, 10);
if (alignment > 0)
{
ss << std::right << std::setw(alignment);
}
else if (alignment < 0)
{
ss << std::left << std::setw(-alignment);
}
}
if (*endptr == ':')
{
fmt = endptr + 1;
}
args[index]->Format(ss, fmt);
return;
}
template <class T>
static void Transfer(ArgArray& argArray, T t)
{
argArray.push_back(new Arg<T>(t));
}
template <class T, typename... Args>
static void Transfer(ArgArray& argArray, T t, Args&&... args)
{
Transfer(argArray, t);
Transfer(argArray, args...);
}
template <typename... Args>
std::string Format(const std::string& format, Args&&... args)
{
if (sizeof...(args) == 0)
{
return format;
}
ArgArray argArray;
Transfer(argArray, args...);
size_t start = 0;
size_t pos = 0;
std::ostringstream ss;
while (true)
{
pos = format.find('{', start);
if (pos == std::string::npos)
{
ss << format.substr(start);
break;
}
ss << format.substr(start, pos - start);
if (format[pos + 1] == '{')
{
ss << '{';
start = pos + 2;
continue;
}
start = pos + 1;
pos = format.find('}', start);
if (pos == std::string::npos)
{
ss << format.substr(start - 1);
break;
}
FormatItem(ss, format.substr(start, pos - start), argArray);
start = pos + 1;
}
return ss.str();
}
}
// #END - format.h
class Player{
protected:
public:
int HP,hp,MP,mp=0,atk,deltaAtk=0,def,deltaDef=0;
std::vector<int> p;
int talentId,talentX,talentY,skillId,skillX,skillY,skillZ;
bool live=true;
int A(){
return std::max(atk+deltaAtk,1);
}
int D(){
return std::max(def+deltaDef,0);
}
void addMp(int delta){
mp = std::min(mp+delta,MP);
}
void addHp(int delta){
hp = std::min(hp+delta,HP);
if(hp<=0){
live = false;
}
}
int calcDamage(int damage,int realDamage){
if(talentId==1){
return std::max(damage-D(),0)+realDamage-realDamage/2;
}
else{
return std::max(damage-D(),0)+realDamage;
}
}
void hurt(int damage,int realDamage){
addMp(1);
if(talentId==1){
int delta=std::max(damage-D(),0)+realDamage-realDamage/2;
addHp(-delta);
}
else{
int delta=std::max(damage-D(),0)+realDamage;
addHp(-delta);
}
}
int getTarget(Player b[]){
while(!p.empty()&&!b[p.front()].live){
p.erase(p.begin());
}
assert(!p.empty());
return p.front();
}
int canActivateSkill(){
if(mp==MP){
return skillId;
}
return -1;
}
void _output(){
if(!live){
std::cerr << " Died.\n";
return;
}
std::cerr << util::Format(" HP: {0}/{1}, MP: {2}/{3}\n",hp,HP,mp,MP)
<< util::Format(" atk: {0}({1}), def: {2}({3})\n",atk,deltaAtk,def,deltaDef)
<< util::Format(" A: {0}, D: {1}\n",A(),D())
<< util::Format(" Talent: {0}, x={1}, y={2}\n",talentId,talentX,talentY)
<< util::Format(" Skill: {0}, x={1}, y={2}, z={3}\n",skillId,skillX,skillY,skillZ);
}
Player(){}
Player(int _HP,int _MP,int _atk,int _def,std::vector<int> _p,
int _talentId,int _talentX,int _talentY,int _skillId,
int _skillX,int _skillY,int _skillZ):
HP(_HP),hp(_HP),MP(_MP),atk(_atk),def(_def),p(_p),
talentId(_talentId),talentX(_talentX),talentY(_talentY),
skillId(_skillId),skillX(_skillX),skillY(_skillY),skillZ(_skillZ){}
};
struct Event{
int start,end,hp,mp,deltaAtk,deltaDef;
bool alice;
Event(){}
Event(int _start,int _end,int _hp,int _mp,int _deltaAtk,int _deltaDef,int _alice):
start(_start),end(_end),hp(_hp),mp(_mp),deltaAtk(_deltaAtk),
deltaDef(_deltaDef),alice(_alice){}
};
int n,currentRound,skill10Used,skill10Limit;
// skill10Used = 1: Alice | skill10Used = 2: Bob
bool aToAlice;
Player Alice[15],Bob[15],*a,*b;
std::vector<Event> roundEndEvents,roundFinishEvents;
namespace Game{
std::string _getTeamName(bool friendly){
if((aToAlice&&friendly)||(!aToAlice&&!friendly)){
return "Alice";
}
return "Bob";
}
void result(){
std::cerr << "\n";
std::cout << currentRound << "\n" << (aToAlice?"Alice\n":"Bob\n");
for(int player=1;player<=n;player++){
std::cout << std::max(a[player].hp,0) << " ";
}
exit(0);
}
void attack(int id,int damage,int realDamage){
b[id].hurt(damage,realDamage);
std::cerr << util::Format(" Attack {0}#{1}, damage: ({2},{3}), {0}#{1}'s hp: {4}\n",
_getTeamName(false),id,damage,realDamage,b[id].hp);
bool live=false;
for(int player=1;player<=n;player++){
live |= b[player].live;
}
if(!live){
result();
}
}
int calcDamage(int current,int target){
if(a[current].talentId==2){
return b[target].calcDamage(a[current].A(),a[current].talentX);
}
else if(a[current].talentId==4){
return b[target].calcDamage(0,a[current].A());
}
return b[target].calcDamage(a[current].A(),0);
}
void normalDamage(int current,int target){
std::cerr << util::Format(" Normal damage, {0}#{1} to {2}#{3}\n",
_getTeamName(true),current,_getTeamName(false),target);
if(a[current].talentId==2){
attack(target,a[current].A(),a[current].talentX);
}
else if(a[current].talentId==4){
attack(target,0,a[current].A());
}
else{
attack(target,a[current].A(),0);
}
}
void skill0(){
std::cerr << " Skill 0 activate\n";
}
void skill1(int x){
std::cerr << " Skill 1 activate, x=" << x << "\n";
for(int player=1;player<=n;player++){
if(b[player].live){
attack(player,x,0);
b[player].mp -= b[player].mp/10;
std::cerr << util::Format(" {0}#{1]'s mp: {2}\n",
_getTeamName(false),player,b[player].mp);
}
}
}
void skill2(int current){
std::cerr << " Skill 2 activate\n";
for(int player=1;player<=n;player++){
if(b[player].live){
attack(player,0,a[current].A());
}
}
}
void skill3(int current,int x){
std::cerr << " Skill 3 activate, x=" << x << "\n";
for(int player=1;player<=n;player++){
if(b[player].live){
attack(player,std::min(b[player].HP/10,x*a[current].A()),0);
}
}
}
void skill4(int x,int y){
std::cerr << util::Format(" Skill 4 activate, x={0}, y={1}\n",x,y);
roundEndEvents.push_back(Event(currentRound,currentRound+x-1,0,y,0,0,aToAlice));
std::cerr << util::Format(" Create round end event #{0} for {1}\n",
roundEndEvents.size(),_getTeamName(true))
<< util::Format(" {0} to {1}, mp: {2}\n",
currentRound,currentRound+x-1,y);
}
void skill5(int current,int x){
std::cerr << " Skill 5 activate, x=" << x << "\n";
int targetPlayer=a[current].getTarget(b);
b[targetPlayer].deltaDef -= x;
std::cerr << util::Format(" {0}#{1}'s deltaDef: {2}\n",
_getTeamName(false),targetPlayer,b[targetPlayer].deltaDef);
attack(targetPlayer,0,a[current].A());
}
void skill6(int current,int x,int y){
std::cerr << util::Format(" Skill 6 activate, x={0}, y={1}\n",x,y);
int targetPlayer=a[current].getTarget(b);
attack(targetPlayer,0,a[current].A());
for(int player=1;player<=n;player++){
if(b[player].live){
b[player].deltaAtk -= y;
std::cerr << util::Format(" {0}#{1]'s deltaAtk: {2}\n",
_getTeamName(false),player,b[player].deltaAtk);
}
}
roundFinishEvents.push_back(Event(currentRound+x-1,currentRound+x-1,0,0,y,0,!aToAlice));
std::cerr << util::Format(" Create round finish event #{0} for {1}\n",
roundFinishEvents.size(),_getTeamName(false))
<< util::Format(" {0} to {1}, deltaAtk: {2}\n",
currentRound+x-1,currentRound+x-1,y);
}
void skill7(int x,int y,int z){
std::cerr << util::Format(" Skill 7 activate, x={0}, y={1}, z={2}\n",x,y,z);
int targetPlayer=0,targetHp=2e9;
for(int player=1;player<=n;player++){
if(a[player].live){
if(a[player].hp<targetHp){
targetHp = a[player].hp;
targetPlayer = player;
}
}
}
a[targetPlayer].addHp(z);
std::cerr << util::Format(" {0}#{1}'s hp: {2}\n",
_getTeamName(true),targetPlayer,a[targetPlayer].hp);
for(int player=1;player<=n;player++){
if(a[player].live){
a[player].deltaAtk += y;
std::cerr << util::Format(" {0}#{1}'s deltaAtk: {2}\n",
_getTeamName(true),player,a[player].deltaAtk);
}
}
roundFinishEvents.push_back(Event(currentRound+x-1,currentRound+x-1,0,0,-y,0,aToAlice));
std::cerr << util::Format(" Create round finish event #{0} for {1}\n",
roundFinishEvents.size(),_getTeamName(true))
<< util::Format(" {0} to {1}, deltaAtk: {2}\n",
currentRound+x-1,currentRound+x-1,-y);
}
void skill8(int current,int x,int y){
std::cerr << util::Format(" Skill 8 activate, x={0}, y={1}\n",x,y);
for(int player=1;player<=n;player++){
if(b[player].live){
attack(player,a[current].A(),0);
}
}
for(int player=1;player<=n;player++){
if(b[player].live){
b[player].deltaDef -= y;
std::cerr << util::Format(" {0}#{1]'s deltaDef: {2}\n",
_getTeamName(false),player,b[player].deltaDef);
}
}
roundFinishEvents.push_back(Event(currentRound+x-1,currentRound+x-1,0,0,0,y,!aToAlice));
std::cerr << util::Format(" Create round finish event #{0} for {1}\n",
roundFinishEvents.size(),_getTeamName(false))
<< util::Format(" {0} to {1}, deltaDef: {2}\n",
currentRound+x-1,currentRound+x-1,y);
}
void skill9(int x,int y,int z){
for(int player=1;player<=n;player++){
if(a[player].live){
a[player].addHp(z);
a[player].deltaDef += y;
std::cerr << util::Format(" {0}#{1]'s hp: {2}, deltaDef: {3}\n",
_getTeamName(true),player,a[player].hp,a[player].deltaDef);
}
}
roundFinishEvents.push_back(Event(currentRound+x-1,currentRound+x-1,0,0,0,-y,aToAlice));
std::cerr << util::Format(" Create round finish event #{0} for {1}\n",
roundFinishEvents.size(),_getTeamName(true))
<< util::Format(" {0} to {1}, deltaDef: {2}\n",
currentRound+x-1,currentRound+x-1,-y);
}
void skill10(int x){
std::cerr << " Skill 10 activate, x=" << x << "\n";
skill10Used = (aToAlice?1:2);
skill10Limit = currentRound+x-1;
std::cerr << util::Format(" {0} activate skill 10, limit: {1}\n",
_getTeamName(true),currentRound+x-1);
for(int player=1;player<=n;player++){
if(a[player].live){
a[player].atk *= 2;
a[player].def *= 2;
a[player].hp = std::max(a[player].HP/2,a[player].hp);
a[player].mp = std::max(a[player].MP/2,a[player].mp);
std::cerr << util::Format(" {0}#{1}'s hp: {2}, mp: {3}\n - atk: {4}, def: {5}\n",
_getTeamName(true),player,a[player].hp,a[player].mp,
a[player].atk,a[player].def);
}
}
roundEndEvents.push_back(Event(currentRound,currentRound+x-1,0,1,0,0,aToAlice));
std::cerr << util::Format(" Create round end event #{0} for {1}\n",
roundEndEvents.size(),_getTeamName(true))
<< util::Format(" {0} to {1}, mp: {2}\n",
currentRound,currentRound+x-1,1);
for(int player=1;player<=n;player++){
if(Alice[player].live&&Alice[player].skillId==10){
Alice[player].skillId = 0;
}
if(Bob[player].live&&Bob[player].skillId==10){
Bob[player].skillId = 0;
}
}
std::cerr << " Disable skill 10\n";
}
void roundStart(){
int targetPlayer=0,targetSkill=-1;
for(int player=n;player>=1;player--){
if(a[player].live){
int currentPlayerSkill=a[player].canActivateSkill();
if(currentPlayerSkill>targetSkill){
targetSkill = currentPlayerSkill;
targetPlayer = player;
}
}
}
if(targetPlayer!=0){
std::cerr << util::Format(" {0}#{1} will activate skill {2}\n Clear {0}#{1}'s mp\n",
_getTeamName(true),targetPlayer,targetSkill);
a[targetPlayer].mp = 0;
int skillX=a[targetPlayer].skillX,skillY=a[targetPlayer].skillY,
skillZ=a[targetPlayer].skillZ;
if(targetSkill==0){
skill0();
}
else if(targetSkill==1){
skill1(skillX);
}
else if(targetSkill==2){
skill2(targetPlayer);
}
else if(targetSkill==3){
skill3(targetPlayer,skillX);
}
else if(targetSkill==4){
skill4(skillX,skillY);
}
else if(targetSkill==5){
skill5(targetPlayer,skillX);
}
else if(targetSkill==6){
skill6(targetPlayer,skillX,skillY);
}
else if(targetSkill==7){
skill7(skillX,skillY,skillZ);
}
else if(targetSkill==8){
skill8(targetPlayer,skillX,skillY);
}
else if(targetSkill==9){
skill9(skillX,skillY,skillZ);
}
else{
skill10(skillX);
}
a[targetPlayer].addMp(1);
std::cerr << util::Format(" {0}#{1}'s mp: {2}\n",
_getTeamName(true),targetPlayer,a[targetPlayer].mp);
if(a[targetPlayer].talentId==5){
a[targetPlayer].addMp(a[targetPlayer].talentY);
std::cerr << util::Format(" Talent 5, {0}#{1}'s mp: {2}\n",
_getTeamName(true),targetPlayer,a[targetPlayer].mp);
}
return;
}
std::vector<int> targetAttackPlayer;
int targetHp=0,targetAttackFinal=0;
for(int player=1;player<=n;player++){
if(a[player].live){
if(b[a[player].getTarget(b)].hp>targetHp){
targetHp = b[a[player].getTarget(b)].hp;
targetAttackPlayer.clear();
}
if(b[a[player].getTarget(b)].hp==targetHp){
targetAttackPlayer.push_back(player);
}
}
}
if(targetAttackPlayer.size()>1){
std::vector<int> targetAttackPlayer2;
int attackHp=0;
for(int target:targetAttackPlayer){
if(calcDamage(target,a[target].getTarget(b))>attackHp){
attackHp = calcDamage(target,a[target].getTarget(b));
targetAttackPlayer2.clear();
}
if(calcDamage(target,a[target].getTarget(b))==attackHp){
targetAttackPlayer2.push_back(target);
}
}
if(targetAttackPlayer2.size()>1){
std::sort(targetAttackPlayer2.begin(),targetAttackPlayer2.end(),
[](int x,int y){return x>y;});
}
targetAttackFinal = targetAttackPlayer2.front();
}
else{
targetAttackFinal = targetAttackPlayer.front();
}
normalDamage(targetAttackFinal,a[targetAttackFinal].getTarget(b));
a[targetAttackFinal].addMp(1);
std::cerr << util::Format(" {0}#{1}'s mp: {2}\n",
_getTeamName(true),targetAttackFinal,a[targetAttackFinal].mp);
if(a[targetAttackFinal].talentId==5){
a[targetAttackFinal].addHp(a[targetAttackFinal].talentX);
std::cerr << util::Format(" Talent 5, {0}#{1}'s hp: {2}\n",
_getTeamName(true),targetAttackFinal,a[targetAttackFinal].hp);
}
}
void roundEnd(){
for(int player=1;player<=n;player++){
if(a[player].live){
a[player].addMp(1);
std::cerr << util::Format(" {0}#{1}'s mp: {2}\n",
_getTeamName(true),player,a[player].mp);
if(a[player].talentId==3){
a[player].addHp(a[player].talentX);
a[player].addMp(a[player].talentY);
std::cerr << util::Format(" Talent 5, {0}#{1}'s hp: {2}, mp: {3}\n",
_getTeamName(true),player,a[player].hp,a[player].mp);
}
}
}
int _eventId=0;
for(Event event:roundEndEvents){
_eventId++;
if(currentRound>=event.start&¤tRound<=event.end&&aToAlice==event.alice){
std::cerr << util::Format(" {0} event #{1}\n",_getTeamName(true),_eventId);
for(int player=1;player<=n;player++){
if(a[player].live){
a[player].addHp(event.hp);
a[player].addMp(event.mp);
a[player].deltaAtk += event.deltaAtk;
a[player].deltaDef += event.deltaDef;
std::cerr << util::Format(" {0}#{1}'s hp: {2}, mp: {3}\n - deltaAtk: {4}, deltaDef: {5}\n",
_getTeamName(true),player,a[player].hp,a[player].mp,
a[player].deltaAtk,a[player].deltaDef);
}
}
}
}
}
void roundFinish(){
if(skill10Limit==currentRound){
std::cerr << "Skill 10 limit\n\n";
std::cout << currentRound << "\n" << (skill10Used==1?"Bob\n":"Alice\n");
for(int player=1;player<=n;player++){
std::cout << std::max((skill10Used==1?Bob[player].hp:Alice[player].hp),0) << " ";
}
exit(0);
}
int _eventId=0;
for(Event event:roundFinishEvents){
_eventId++;
std::cerr << util::Format(" {0} event #{1}\n",(event.alice?"Alice":"Bob"),_eventId);
if(currentRound>=event.start&¤tRound<=event.end){
if(event.alice){
for(int player=1;player<=n;player++){
if(Alice[player].live){
Alice[player].addHp(event.hp);
Alice[player].addMp(event.mp);
Alice[player].deltaAtk += event.deltaAtk;
Alice[player].deltaDef += event.deltaDef;
std::cerr << util::Format(" Alice#{0}'s hp: {1}, mp: {2}\n - deltaAtk: {3}, deltaDef: {4}\n",
player,Alice[player].hp,Alice[player].mp,Alice[player].deltaAtk,Alice[player].deltaDef);
}
}
}
else{
for(int player=1;player<=n;player++){
if(Bob[player].live){
Bob[player].addHp(event.hp);
Bob[player].addMp(event.mp);
Bob[player].deltaAtk += event.deltaAtk;
Bob[player].deltaDef += event.deltaDef;
std::cerr << util::Format(" Bob#{0}'s hp: {1}, mp: {2}\n - deltaAtk: {3}, deltaDef: {4}\n",
player,Bob[player].hp,Bob[player].mp,Bob[player].deltaAtk,Bob[player].deltaDef);
}
}
}
}
}
}
}
Player getPlayerFromInput();
int main(){
std::cerr << "Input start -------------------\n";
std::cin >> n;
std::cerr << "n = " << n << "\n";
for(int i=1;i<=n;i++){
Alice[i] = getPlayerFromInput();
std::cerr << util::Format("Alice {0}/{1}:\n",i,n);
Alice[i]._output();
}
for(int i=1;i<=n;i++){
Bob[i] = getPlayerFromInput();
std::cerr << util::Format("Bob {0}/{1}:\n",i,n);
Bob[i]._output();
}
std::cerr << "Input end ---------------------\n\n";
for(currentRound=1;currentRound<=23333;currentRound++){
std::cerr << "Round " << currentRound << ":\n";
aToAlice = true;
a = Alice;
b = Bob;
std::cerr << " Alice start\n";
Game::roundStart();
std::cerr << " Alice end\n";
Game::roundEnd();
aToAlice = false;
a = Bob;
b = Alice;
std::cerr << " Bob start\n";
Game::roundStart();
std::cerr << " Bob end\n";
Game::roundEnd();
std::cerr << " Finish\n";
Game::roundFinish();
std::cerr << "Round " << currentRound << " finish\n\n";
for(int i=1;i<=n;i++){
std::cerr << util::Format("Alice {0}/{1}:\n",i,n);
Alice[i]._output();
}
for(int i=1;i<=n;i++){
std::cerr << util::Format("Bob {0}/{1}:\n",i,n);
Bob[i]._output();
}
std::cerr << "\n";
}
std::cout << "QAQ";
return 0;
}
Player getPlayerFromInput(){
int HP,MP,atk,def,tf,x,y,jn,_x,_y,_z;
std::vector<int> p;
std::cin >> HP >> MP >> atk >> def;
for(int j=1;j<=n;j++){
int _;
std::cin >> _;
p.push_back(_);
}
std::cin >> tf >> x >> y >> jn >> _x >> _y >> _z;
return Player(HP,MP,atk,def,p,tf,x,y,jn,_x,_y,_z);
}