ACPC 2013 Problem H. Super Ants
Problem H. Super Ants
简单题意:
有这么个地图,每个坐标都有一颗糖,糖有一个0-9的价值
地图中有一只蚂蚁,能够进行分裂,每次分裂能向8个方向分裂出一段距离
具体来说,蚂蚁可以使用t秒的时间分裂到d的距离,其中d=max(abs(x0-x),abs(y0-y)),记住只能8方向!!!(也就是题给的图)
而新分裂出来的蚂蚁又可以进行分裂,分裂的规则不变
同一只蚂蚁不能在同一个格子里分裂多次,任何一个格子在任何时候都可以有任意多的蚂蚁
当时间不够分裂,蚂蚁们会得到所在格子糖的价值,问最终所有蚂蚁得到的价值是多少
思路:
动态规划(+结合样例多读几遍题)(你想管它叫模拟好像也不是不行)
思维:
蚂蚁分裂相当于读条,需要1s的分裂和需要2s的分裂同时开始!!!
同时开始!!! 同时开始!!! 同时开始!!!(千万记住)
光题意就卡了我好久的一道题,当我们理解了题意,它的难度就降下来了(一点)
定义a[i][j][k],b[i][j][k],其中i,j表示在图中的坐标,k分情况讨论:
当k=0-7时,k表示向8个方向之一分裂的状态
当k=8时,k表示向所有方向分裂的状态,也就是该秒末时的状态
当k=9时,k表示该秒初,亦即上一秒末的状态
b仅表示该秒分裂得到的新蚂蚁,而a表示b+得到b状态的蚂蚁(也就是该秒总蚂蚁)
下面一段可能需要很强的理解能力来理解我啥也不是的表达()
我们模拟时间的递减,那么可以根据该秒初a[i][j][k],a[i][j][8],a[i][j][9]的状态算出b[i-1][j-1][k],b[i-1][j][k]...的状态
也就是8个方向都同时新得到t只蚂蚁,t=a[i][j][8]-a[i][j][9]+a[i][j][k](该秒初所有蚂蚁分裂,上一秒初分裂过的蚂蚁不能再算一遍)
得到b之后,我们只需要把b(该秒新得到的)加到a(该秒原有的)就能得到新的a(该秒最终状态)
最后我们知道了每个格子有多少蚂蚁,只需要循环一遍所有格子,就能得到最终蚂蚁得到的价值了
最后是代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int mod=1e9+7; int dx[10]={-1,-1,-1,0,1,1,1,0},dy[10]={-1,0,1,1,1,0,-1,-1}; int a[55][55][10],b[55][55][10]; int main() { int t,n,m,s,x,y; scanf("%d",&t); while(t--) { scanf("%d%d%d%d%d",&n,&m,&s,&x,&y); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) for(int k=0;k<10;++k) a[i][j][k]=0; a[x][y][8]=1; while(s--) { for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { for(int k=0;k<8;++k) { int di=i+dx[k],dj=j+dy[k]; if(unsigned(di)<=n && unsigned(dj)<=m) { int tt=((ll)a[i][j][8]-a[i][j][9]+a[i][j][k]+mod)%mod; (b[di][dj][8]+=tt)%=mod; (b[di][dj][k]+=tt)%=mod; } } } } for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { for(int k=0;k<8;++k) { a[i][j][k]=b[i][j][k]; b[i][j][k]=0; } a[i][j][9]=a[i][j][8]; (a[i][j][8]+=b[i][j][8])%=mod; b[i][j][8]=0; } } } ll ans=0; for(int i=1;i<=n;++i) { for(int j=1;j<=m;++j) { int r; scanf("%d",&r); ans=(ans+(ll)r*a[i][j][8])%mod; } } printf("%lld\n",ans); } }