【题解】洛谷 P8874 [传智杯 #5 初赛] F-二人的大富翁游戏

洛谷 P8874 [传智杯 #5 初赛] F-二人的大富翁游戏

题目链接
大模拟,模拟就完事了

数组的解释

题目中的坐标为1到n,为了方便取模操作我们使用0到n-1
c [ i ] [ j ] c[i][j] c[i][j]表示位于位置 i i i的建筑物从 j − 1 j-1 j1升级到 j j j的花费
s [ i ] [ j ] s[i][j] s[i][j]表示位于位置 i i i的建筑物从 0 0 0升级到 j j j的花费
d [ i ] d[i] d[i]表示位于位置 i i i的建筑物回合末提供给拥有者的资金
s t [ i ] st[i] st[i]表示位于位置 i i i的建筑物的拥有者
其中 s t [ i ] = 1 st[i]=1 st[i]=1表示建筑物 i i i被莲子占有, s t [ i ] = 2 st[i]=2 st[i]=2表示建筑物 i i i被梅莉占有
l e v e l [ i ] level[i] level[i]表示建筑物 i i i的等级

c u r = 1 / 2 cur=1/2 cur=1/2表示当前轮到莲子/梅莉
p o s [ 1 / 2 ] pos[1/2] pos[1/2]表示莲子/梅莉的坐标
m o n e y [ 1 / 2 ] money[1/2] money[1/2]表示莲子/梅莉的钱

s [ i ] [ j ] s[i][j] s[i][j]可由前缀和求得 s [ i ] [ j ] = s [ i ] [ j − 1 ] + c [ i ] [ j ] s[i][j]=s[i][j-1]+c[i][j] s[i][j]=s[i][j1]+c[i][j]

操作过程

在读入操作序列的时候需要注意读入操作
当op=1时

  1. 当读入两次op=1时表示,一个回合结束,应将每个人占有的建筑物的收益加上
  2. 转换当前进行移动的人,这里使用 c u r = c u r % 2 + 1 cur=cur\%2+1 cur=cur%2+1进行转换(或者 c u r = 3 − c u r cur=3-cur cur=3cur也是可以的)
    • c u r = 1 cur=1 cur=1 c u r % 2 + 1 = 2 cur\%2+1=2 cur%2+1=2
    • c u r = 2 cur=2 cur=2 c u r % 2 + 1 = 1 cur\%2+1=1 cur%2+1=1
  3. 这里要注意前进的时候注意做取模操作,从起点到终点的每一步都需要做判断建筑物带给自己的损失和收益。

当op=2时

  1. 判断当前建筑物是否是自己的或者未占有的,将建筑物提升到可以提升到的最大等级
  2. s t [ ] st[] st[]数组标记为自己,需要注意的一点,当建筑物至少提升1级时,才可以将建筑物标记

第一次写题解,还有许多不足,希望大家多多指教 ⌣ \smile

#include <iostream>
#include <vector>
using namespace std;

#define int long long
typedef pair<int,int> PII;
const int MAXN=100+10;
int c[MAXN][MAXN];
int s[MAXN][MAXN];
int d[MAXN];
int st[MAXN];
int level[MAXN];

signed main()
{
	int n,m,q,L;
	cin>>n>>m>>q>>L;
	for(int i=0;i<n;i++)
	{
		for(int j=1;j<=L;j++)
		{
			cin>>c[i][j];
			s[i][j]=s[i][j-1]+c[i][j];
		}
	}
	for(int i=0;i<n;i++)
	{
		cin>>d[i];
	}
	vector<PII> seq;
	int op,x;
	while(cin>>op>>x)
	{
		if(op==0)
			break;
		seq.push_back({op,x});
	}
	int cur=1;
	int pos[3]={0,0,0};
	int money[3]={m,m,m};
	bool lose[3]={0,0,0};
	int cnt=0;
	for(int i=0;i<seq.size();i++)
	{
		int op=seq[i].first;
		if(op==1)
		{
			if(cnt%2==0)
			{
				for(int t=0;t<n;t++)
				{
					if(st[t]!=0)
					{
						money[st[t]]+=d[t];
					}
				}
			}
			cnt++;
			if(i>0)
				cur=cur%2+1;
			
			int k=seq[i].second;
			int current_pos=pos[cur];
			for(int i=0;i<k;i++)
			{
				current_pos=(current_pos+1)%n;
				if(st[current_pos]==0)
					continue;
				else if(st[current_pos]!=cur)
				{
					money[cur]-=s[current_pos][level[current_pos]];
					money[cur%2+1]+=s[current_pos][level[current_pos]];
				}
				else if(st[current_pos]==cur)
				{
					money[cur]+=s[current_pos][level[current_pos]];
				}
				if(money[cur]<0)
				{
					if(cur==1)
						cout<<"Renko\n";
					else if(cur==2)
						cout<<"Merry\n";
					return 0;
				}
			}
			pos[cur]=(pos[cur]+k)%n;
		}
		else if(op==2)
		{
			int k=seq[i].second;
			int current_pos=pos[cur];
			if(st[current_pos]==cur||st[current_pos]==0)
			{
				int current_level=level[current_pos];
				int want_level=min(L,current_level+k);
				for(int i=want_level;i>current_level;i--)
				{
					int cost=s[current_pos][i]-s[current_pos][current_level];
					if(money[cur]>=cost)
					{
						money[cur]-=cost;
						st[current_pos]=cur;
						level[current_pos]=i;
						break;
					}
				}
			}
		}
	}
	
	for(int t=0;t<n;t++)
	{
		if(st[t]!=0)
		{
			money[st[t]]+=d[t];
		}
	}
	cout<<money[1]<<' '<<money[2]<<'\n';
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值