2973 石頭遊戲

題面

題意

給出一個方格陣,初始每個格子中都沒有石頭,然後每個格子都有一個操作序列,並且每時刻執行一個,循環執行,序列長度小於等於6,問T時刻後石頭個數最多的格子中有幾個石頭。

做法

因爲操作序列長度小於等於6,所以每60次操作必有一次循環,所以可以對60次操作建一個矩陣,由60次操作相乘,矩陣的長寬均爲方格矩陣的元素總數,操作均可以用矩陣中的數字來表示,其中0號點用來表示所有石頭的源頭,然後矩陣快速冪即可。

代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 70
using namespace std;

ll m,n,tot,T,K,ans,num[N][N],len[N];
char cz[N][N];
struct Jz
{
	ll num[N][N];
	Jz(){memset(num,0,sizeof(num));}
	Jz operator * (const Jz &u) const
	{
		ll i,j,k;
		Jz res;
		for(i=0;i<=tot;i++)
		{
			for(j=0;j<=tot;j++)
			{
				for(k=0;k<=tot;k++)
				{
					res.num[i][j]+=num[i][k]*u.num[k][j];
				}
			}
		}
		return res;
	}
	void out()
	{
		ll i,j;
		for(i=0;i<=tot;i++)
		{
			for(j=0;j<=tot;j++)
			{
				printf("%-3lld",num[i][j]);
			}
			puts("");
		}
		puts("");
	}
}qz[N],jz;

inline ll zh(ll u,ll v){return (u-1)*n+v;}

inline Jz po(Jz u,ll v)
{
	ll i;
	Jz res;
	for(i=0;i<=tot;i++) res.num[i][i]=1;
	for(;v;)
	{
		if(v&1) res=res*u;
		u=u*u;
		v>>=1;
	}
	return res;
}

int main()
{
	ll i,j,k;
	char t;
	cin>>m>>n>>T>>K;
	tot=m*n;
	for(i=1;i<=m;i++)
	{
		for(j=1;j<=n;j++)
		{
			scanf("%1lld",&num[i][j]);
			num[i][j]++;
		}
	}
	for(i=1;i<=K;i++)
	{
		scanf("%s",cz[i]);
		len[i]=strlen(cz[i]);
	}
	for(i=0;i<=tot;i++) qz[0].num[i][i]=1;
	for(i=1;i<=60;i++)
	{
		qz[i].num[0][0]=1;
		for(j=1;j<=m;j++)
		{
			for(k=1;k<=n;k++)
			{
				t=cz[num[j][k]][(i-1)%len[num[j][k]]];
				if(t>='0'&&t<='9')
				{
					qz[i].num[zh(j,k)][zh(j,k)]=1;
					qz[i].num[0][zh(j,k)]=t-'0';
				}
				else if(t=='N'&&j>1) qz[i].num[zh(j,k)][zh(j-1,k)]=1;
				else if(t=='S'&&j<m) qz[i].num[zh(j,k)][zh(j+1,k)]=1;
				else if(t=='E'&&k<n) qz[i].num[zh(j,k)][zh(j,k+1)]=1;
				else if(t=='W'&&k>1) qz[i].num[zh(j,k)][zh(j,k-1)]=1;
			}
		}
		qz[i]=qz[i-1]*qz[i];
	}
	jz.num[0][0]=1;
	jz=jz*po(qz[60],T/60)*qz[T%60];
	for(i=1;i<=tot;i++) ans=max(ans,jz.num[0][i]);
	cout<<ans;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章