昆特牌 解题报告
昆特牌
题目背景
什么?你还有一场 NOIP 模拟赛? 什么都别说,先来盘昆特牌吧!
题目描述
昆特牌是一款双人对战卡牌游戏,游戏规则现简化如下:
游戏简化为仅有一局;
每位牌手有三行,分别是近战、远程和攻城;
每位牌手每次按顺序出一张牌;
每位牌手有同样数量张牌,而聪明的你能预知对手每次出的牌!
牌分为以下几种功能:
- 单位牌:有一个点数和放置位置,\(0\)、\(1\)、\(2\)分别表示近战、远程和攻城,放置在你的场上;
- 天气牌:有一个影响位置\(0\)、\(1\)、\(2\)分别表示近战、远程和攻城, 对你的和对手的相应行都会影响。天气下的单位无法被烧灼(烧灼下面有解释),天气下的单位计算点数和的时候视为每个为\(1\),对已经有天气牌的行使用视作无效;
- 反天气牌:去除所有的天气牌并去除天气牌的视为每个为\(1\)效果(当然也包括其他效果);
- 烧灼牌:消灭全场现有战力最高的单位(包括自己的单位)(除了天气下的), 若有多个则都消灭,若没有单位则视为无效,后续放入同行的单位仍然视作被天气影响;
- 号角牌:选择\(6\)行(包括对手的)中一行使该行现有单位战力翻倍,但不能对天气牌影响下的行使用。如果每行都有天气视作无效,否则必须选择一行。由于丢了一些牌,这种卡最多只会出现 2 张,而且只有你有。这种牌视为立刻生效,然后消失;
所有牌都必须使用,且除了单位牌其他牌都没有点数。视作无效的牌不影响整个出牌过程,打出它什么用都没有,但你还是打出了它。
你想要让最后你的点数和减去对手的尽量大(不是绝对值!),该怎么办呢?
输入输出格式
输入格式
第一行两个数\(W,N\)分别表示先后手和每人牌数,\(W=0\)表示你先手,\(W=1\)表示对手先。
接下来依次\(N\)行表示对手每次出的牌:
- \(t=1\),这是一张单位牌,接下来\(x,y\)分别表示战力和位置;
- \(t=2\),这是一张天气牌,接下来\(x\)表示位置;
- \(t=3\),这是一张反天气牌;
- \(t=4\),这是一张烧灼牌;
- \(t=5\),这是一张号角牌。
接下来\(N\)行表示你的牌,描述同上。
输出格式
点数和差的最大值和点数和差最大方案数,用空格分隔。
号角放在不同行算不同方案(无效不算放在一行,但也是一种方案,同 012 行不同),且每张牌是不同的。
例如你有两种方案:第一张号角放在你的 1 行第二张号角放在你的 0 行与第一张号角放在你的 0 行第二张号角放在你的 1 行不同。
数据范围
对于\(10\%\)的数据,\(t\in\{1\}\)
对于\(20\%\)的数据,\(t\in\{1,2\}\)
对于\(40\%\)的数据,\(t\in\{1,2,3\}\)
对于\(60\%\)的数据,\(t\in\{1,2,3,4\}\)
对于\(100\%\)的数据,\(N\le 7,1\le\)所有单位战力\(\le 1000\)
TIPS
好好读题!
好好读题!
好好读题!
要是联赛来这么一道大模拟我就飞了(flag
首先读错题了,以为自己出牌的顺序也是给定好了。其次回溯时没想好怎么存原来的状态瞎搞了。
以后做这种题一定要先想好,把题目读清楚,把大致思路理清楚,对怎么写大致有个结构认识再动笔
也算是提醒了我自己,搜索时的状态如果理不太清楚直接开另外一个东西把状态存下来,待会再还回去。反正系统栈不差你这点东西。
思路(流程):
- 用\(\tt{next\_permutation()}\)直接搞自己出牌的全排列
- 搜索自己和敌方出牌
- 用\(\tt{vector}\)存每个人每一行的战斗力
- 加人时\(\tt{tmp}\)存一下一行的,搜完了还回去
- 天气一样,存一下
- 砍最大值可以先存下来,然后\(\tt{sort}\)先找到,再去删掉
学习了一些有关\(\tt{vector}\)的姿势
vector <int> a;
a.pop_back();
a.front();
a.back();
Code:
#include <cstdio>
#include <vector>
#include <algorithm>
std::vector <int > dw[2][3];
struct node
{
int id,op,x,y;
bool friend operator <(node n1,node n2){return n1.id<n2.id;}
}opt[2][10];
int weather[3],n,w;
int cal()
{
int c[2]={0,0};
for(int i=0;i<=2;i++)
for(int k=0;k<=1;k++)
{
if(weather[i])
c[k]+=dw[k][i].size();
else
for(int p=0;p<dw[k][i].size();p++)
c[k]+=dw[k][i][p];
}
return c[0]-c[1];
}
int max(int x,int y){return x>y?x:y;}
int mxa=-0x3f3f3f3f,ans;
void dfs(int who,int dep)
{
if(dep==n+1)
{
int d=cal();
if(mxa<d) mxa=d,ans=1;
else if(mxa==d) ++ans;
return;
}
if(opt[who][dep].op==1)
{
int x=opt[who][dep].x,y=opt[who][dep].y;
std::vector <int > tmp=dw[who][y];
dw[who][y].push_back(x);
dfs(who^1,dep+(who!=w));
dw[who][y]=tmp;
}
else if(opt[who][dep].op==2)
{
int x=opt[who][dep].x;
int tmp=weather[x];
weather[x]=1;
dfs(who^1,dep+(who!=w));
weather[x]=tmp;
}
else if(opt[who][dep].op==3)
{
int tmp[3];
for(int i=0;i<=2;i++) tmp[i]=weather[i],weather[i]=0;
dfs(who^1,dep+(who!=w));
for(int i=0;i<=2;i++) weather[i]=tmp[i];
}
else if(opt[who][dep].op==4)
{
int mx=0;
std::vector <int> tmp[2][3];
for(int i=0;i<=2;i++)
{
if(!weather[i])
{
for(int k=0;k<=1;k++)
{
tmp[k][i]=dw[k][i];
std::sort(dw[k][i].begin(),dw[k][i].end());
if(!dw[k][i].empty()) mx=max(mx,dw[k][i].back());
}
}
}
for(int i=0;i<=2;i++)
if(!weather[i])
for(int k=0;k<=1;k++)
while(!dw[k][i].empty()&&dw[k][i].back()==mx) dw[k][i].pop_back();
dfs(who^1,dep+(who!=w));
for(int i=0;i<=2;i++)
if(!weather[i])
for(int k=0;k<=1;k++)
dw[k][i]=tmp[k][i];
}
else
{
for(int i=0;i<=2;i++)
{
if(!weather[i])
for(int k=0;k<=1;k++)
{
for(int p=0;p<dw[k][i].size();p++)
dw[k][i][p]*=2;
dfs(who^1,dep+(who!=w));
for(int p=0;p<dw[k][i].size();p++)
dw[k][i][p]/=2;
}
}
if(weather[0]&weather[1]&weather[2]) dfs(who^1,dep+(who!=w));
}
}
int main()
{
scanf("%d%d",&w,&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&opt[1][i].op);
if(opt[1][i].op==1)
scanf("%d%d",&opt[1][i].x,&opt[1][i].y);
if(opt[1][i].op==2)
scanf("%d",&opt[1][i].x);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&opt[0][i].op);
if(opt[0][i].op==1)
scanf("%d%d",&opt[0][i].x,&opt[0][i].y);
if(opt[0][i].op==2)
scanf("%d",&opt[0][i].x);
opt[0][i].id=i;
}
dfs(w,1);
while(std::next_permutation(opt[0]+1,opt[0]+1+n))
dfs(w,1);
printf("%d %d\n",mxa,ans);
return 0;
}
2018.11.6