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);
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/hntk/p/12808013.html