P8874 二人的大富翁游戏
题目
小模拟,题目看懂就结束了
但我没看懂,orz
警示后人:
- 路上经过的每一个点都要判断建筑属于谁并判断得钱还是交钱
- 交钱要交到对方手里
- 两个人都操作完才算一回合,是否进入下一回合的判断要在if(x==1)里面
- 注意 判断升级边界的代码 的位置
- 初始资金别忘了(悲)
- 一个建筑的价值(题目中的\(a_i\))等于你在这建筑上消耗的总钱数
- 输入的时候判断游戏何时结束(尽管题目上说操作1的次数恰好等于2*回合数,但无法判断后面是否跟着一个2操作,所以还是要写!=EOF)
小技巧:给自己写注释是好习惯,尤其是模拟
代码(带注释)
#include<bits/stdc++.h>
using namespace std;
#define int long long //竟然要开long long
int n,m,q,l; //格子数、初始资金、回合数、建筑物等级上限
int a[111]; //走到第 i 格时,如果是自己的则获得 a[i][j] 元,是对方的则支付 a[i][j] 元
int c[111][111]; //第 i 格建筑升到 j+1 级所需价钱
int d[111]; //每回合第 i 格建筑提供资金
int b[111]; //第 i 格建筑属于谁(1=莲子/0=梅莉/-1=没有)
int e[111]; //第 i 格建筑当前等级(初始为 -1)
int x,k; //行动种类、行动次数(x=1 时切换行动方,行动方走到第 now+k 格;x=2 时当前行动方对第 i 格建筑升 k 级)
bool t; //当前行动方(1=莲子/0=梅莉)
int p[2]; //当前所在位置(1=莲子/0=梅莉)
int y[2]; //当前持有的钱数(1=莲子/0=梅莉)
int h[2]; //判断是否进入下一回合(本回合两人都已行动过一次后 x==1 时进入下一回合)
void __pre() //初始化
{
scanf("%lld%lld%lld%lld",&n,&m,&q,&l);
for(int i=1;i<=n;++i)
{
for(int j=0;j<l;++j)
{
scanf("%lld",&c[i][j]);
}
}
for(int i=1;i<=n;++i) scanf("%lld",&d[i]);
// memset(e,-1,sizeof(e)); //这个初始化是 0 (从 -1 开始会很麻烦但不是不行)
memset(b,-1,sizeof(b));
p[0]=p[1]=1; //起点是 1
y[0]=y[1]=m;
}
void __turn() //回合结算
{
if(h[0]&&h[1])
{
for(int i=1;i<=n;++i)
{
if(b[i]==1) y[1]+=d[i];
if(b[i]==0) y[0]+=d[i];
}
h[0]=h[1]=0;
}
}
void __move() //移动
{
while(k--)
{
p[t]++; //路过的所有地方都要判(见样例解释)
if(p[t]>n) p[t]-=n;
if(b[p[t]]==t)
{
y[t]+=a[p[t]]; //是自己的得钱
}
if(b[p[t]]==(!t))
{
y[t]-=a[p[t]]; //不是自己的交钱
y[(!t)]+=a[p[t]];
}
if(y[t]<0) //判断是否结束,可以证明只有移动操作会把钱扣到负数
{
t?puts("Renko"):puts("Merry"); //输出负的那个
exit(0);
}
}
}
void __powerup() //升级建筑
{
if(b[p[t]]==t||b[p[t]]==-1)
{
for(int i=1;i<=k;++i)
{
if(e[p[t]]==l) return; //这个写错位置就寄了
if(y[t]>=c[p[t]][e[p[t]]])
{
y[t]-=c[p[t]][e[p[t]]];
a[p[t]]+=c[p[t]][e[p[t]]]; //升级
e[p[t]]++; //这个写错位置也寄
if(b[p[t]]==-1) b[p[t]]=t; //购买
}
}
}
}
#undef int
int main()
{
__pre();
//上面是初始化
//开始游戏
while(scanf("%lld",&x)!=EOF)
{
scanf("%lld",&k);
if(x==1)
{
__turn();
t=!t; //切换行动方
h[t]=1;
__move();
}
if(x==2)
{
__powerup();
}
}
h[1]=h[0]=1; //最后一回合也要结算(不然样例 2 会死)
__turn();
printf("%lld %lld\n",y[1],y[0]);
}
代码(附调试过程中用到的东西)
#include<bits/stdc++.h>
using namespace std;
#define int long long //竟然要开long long
int n,m,q,l; //格子数、初始资金、回合数、建筑物等级上限
int a[111]; //走到第 i 格时,如果是自己的则获得 a[i][j] 元,是对方的则支付 a[i][j] 元
int c[111][111]; //第 i 格建筑升到 j+1 级所需价钱
int d[111]; //每回合第 i 格建筑提供资金
int b[111]; //第 i 格建筑属于谁(1=莲子/0=梅莉/-1=没有)
int e[111]; //第 i 格建筑当前等级(初始为 -1)
int x,k; //行动种类、行动次数(x=1 时切换行动方,行动方走到第 now+k 格;x=2 时当前行动方对第 i 格建筑升 k 级)
bool t; //当前行动方(1=莲子/0=梅莉)
int p[2]; //当前所在位置(1=莲子/0=梅莉)
int y[2]; //当前持有的钱数(1=莲子/0=梅莉)
int h[2]; //判断是否进入下一回合(本回合两人都已行动过一次后 x==1 时进入下一回合)
//带 test 的函数是调试的时候用的
#define test_place() t?printf("Renko in the %lld.\n",p[t]):printf("Merry in the %lld.\n",p[t]);
#define test_money() printf("Renko has %lld yuan\n",y[1]),printf("Merry has %lld yuan\n",y[0]);
void test_got(int id,int mny)
{
id?printf("Renko got %lld yuan\n",mny):printf("Merry got %lld yuan\n",mny);
}
void test_lost(int id,int mny)
{
id?printf("Renko lost %lld yuan\n",mny):printf("Merry lost %lld yuan\n",mny);
}
void test_pwup(int pos,int lv)
{
t?printf("Renko changes %lld to lv.%lld\n",pos,lv):printf("Merry changes %lld to lv.%lld\n",pos,lv);
}
void test_belong()
{
printf("Renko: ");
for(int i=1;i<=n;++i) if(b[i]==1) printf("%lld ",i);
puts("");
printf("Merry: ");
for(int i=1;i<=n;++i) if(b[i]==0) printf("%lld ",i);
puts("");
}
void __pre() //初始化
{
scanf("%lld%lld%lld%lld",&n,&m,&q,&l);
for(int i=1;i<=n;++i)
{
for(int j=0;j<l;++j)
{
scanf("%lld",&c[i][j]);
}
}
for(int i=1;i<=n;++i) scanf("%lld",&d[i]);
// memset(e,-1,sizeof(e)); //这个初始化是 0 (从 -1 开始会很麻烦但不是不行)
memset(b,-1,sizeof(b));
p[0]=p[1]=1; //起点是 1
y[0]=y[1]=m;
}
void __turn() //回合结算
{
if(h[0]&&h[1])
{
// test_money();
// test_belong();
// int g1=0,g2=0;
for(int i=1;i<=n;++i)
{
if(b[i]==1)
{
y[1]+=d[i];
// g1+=d[i];
}
if(b[i]==0)
{
y[0]+=d[i];
// g2+=d[i];
}
}
h[0]=h[1]=0;
// test_got(1,g1);
// test_got(0,g2);
}
}
void __move() //移动
{
while(k--)
{
p[t]++; //路过的所有地方都要判(见样例解释)
if(p[t]>n) p[t]-=n;
// test_place();
if(b[p[t]]==t)
{
y[t]+=a[p[t]]; //是自己的得钱
// test_got(t,a[p[t]]);
}
if(b[p[t]]==(!t))
{
y[t]-=a[p[t]]; //不是自己的交钱
y[(!t)]+=a[p[t]];
// test_lost(t,a[p[t]]),test_got((!t),a[p[t]]);
}
if(y[t]<0) //判断是否结束,可以证明只有移动操作会把钱扣到负数
{
t?puts("Renko"):puts("Merry"); //输出负的那个
exit(0);
}
}
}
void __powerup() //升级建筑
{
if(b[p[t]]==t||b[p[t]]==-1)
{
for(int i=1;i<=k;++i)
{
if(e[p[t]]==l) return; //这个写错位置就寄了
if(y[t]>=c[p[t]][e[p[t]]])
{
y[t]-=c[p[t]][e[p[t]]];
a[p[t]]+=c[p[t]][e[p[t]]]; //升级
// test_pwup(p[t],e[p[t]]);
// test_lost(t,c[p[t]][e[p[t]]]);
e[p[t]]++; //这个写错位置也寄
if(b[p[t]]==-1) b[p[t]]=t; //购买
}
}
}
}
#undef int
int main()
{
__pre();
//上面是初始化
//开始游戏
while(scanf("%lld",&x)!=EOF)
{
scanf("%lld",&k);
if(x==1)
{
__turn();
t=!t; //切换行动方
h[t]=1;
__move();
}
if(x==2)
{
__powerup();
}
// test_money();
// printf("%lld %lld\n",y[1],y[0]);
}
h[1]=h[0]=1; //最后一回合也要结算(不然样例 2 会死)
__turn();
printf("%lld %lld\n",y[1],y[0]);
}