party

Portal -->broken qwq

Description

  这次怪兽大M受各路怪兽邀请参加聚会,被大M欺压的人类抓住机会想用陷阱抓捕大M。     可以将地图看作一个长n宽m的坐标系,大M在一开始处于(1,1)位置对于每一个时刻,大M可以朝上下左右走,或者不动。你作为人类的程序猿,被派出计算大M能参加聚会又能避开陷阱的方案数。你将接到总共q个3种类型的指令:  

  1:x,y,t——人类截获怪兽的电报,发现大M将在t时刻参加一个位于(x,y)位置的舞会,保证(x,y)位置不存在一个陷阱。  

​  2:x,y,t——人类在第t时刻在(x,y)位置放置了一个陷阱,保证(x,y)位置之前不存在一个陷阱。  

  3:x,y,t——人类在第t时刻在(x,y)位置撤去了一个陷阱,保证(x,y)位置之前存在一个陷阱。  

  对于每个类型1的指令,你需要输出大M从(1,1)出发,既能避开陷阱,又能参加舞会的方案数。因为这个方案数可能很大,你只需要输出方案数对10^9+7取模的余数。

  

  数据范围:1<=n*m<=20,1<=q<=1000 ,所有指令中2<=t<=10^9,保证各指令按t升序给出

  

Solution

(一开始看错题了以为只能往右或上走很开心敲完发现。。果然自己还是太naive。。。)

​  转移的话可以从上下左右以及自己转过来。。那。。比较容易想到矩乘吧

​  然后转移矩阵在更改陷阱情况的时候会改变,但是中间那段时间(也就是两次操作的间隔)是不变的,这段时间里面就直接用快速幂乘起来然后乘到答案里面去

  不要想着在每次询问的时候再求答案。。而是应该一路计算上去。。(怎么感觉好久没写这种题了然后开始智力退化。。一开始居然没想到。。我可能没救了qwq)

  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=30,MOD=1e9+7;
const int dx[5]={0,-1,0,1,0},dy[5]={0,0,1,0,-1};
void add(int &x,int y){x=(1LL*x+MOD+y)%MOD;}
int mul(int x,int y){return 1LL*x*y%MOD;}
struct Mtrix{/*{{{*/
    int a[N][N];
    int n;
    void init(int _n){n=_n;memset(a,0,sizeof(a));}
    void setUnit(int _n){
        n=_n;
        for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) a[i][j]=i==j;
    }
    friend Mtrix operator * (Mtrix x,Mtrix y){
        Mtrix ret;
        ret.init(x.n);
        for (int i=1;i<=ret.n;++i)
            for (int j=1;j<=ret.n;++j){
                for (int k=1;k<=ret.n;++k)
                    add(ret.a[i][j],mul(x.a[i][k],y.a[k][j]));
            }
        return ret;
    }
}ans,trans,ret,base;/*}}}*/
int ok[N][N];
int n,m,last,q;
int Id(int x,int y){return (x-1)*m+y;}
bool check(int x,int y){
    if (x<1||x>n||y<1||y>m) return false;
    return true;
}
void fill(){
    int now,tmp,x,y;
    trans.init(n*m);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j){
            if (!ok[i][j]) continue;
            now=Id(i,j);
            for (int d=0;d<5;++d){
                x=i+dx[d]; y=j+dy[d];
                if (!check(x,y)) continue;
                tmp=Id(x,y);
                trans.a[now][tmp]+=ok[x][y];
            }
        }
}
void ksm(int y){
    ret.setUnit(n*m); base=trans;
    for (;y;y>>=1,base=base*base)
        if (y&1) ret=ret*base;
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    scanf("%d%d%d",&n,&m,&q);
    for (int i=1;i<=n;++i)
        for (int j=1;j<=m;++j)
            ok[i][j]=1;
    int x,y,t,op;
    last=1;
    ans.init(n*m);
    ans.a[1][1]=1;
    fill();
    for (int i=1;i<=q;++i){
        scanf("%d%d%d%d",&op,&x,&y,&t);
        if (op==1){
            ksm(t-last);
            ans=ans*ret;
            printf("%d\n",ans.a[Id(1,1)][Id(x,y)]);
            last=t;
        }
        else if (op==2){
            ksm(t-last);
            ans=ans*ret;
            last=t;
            ok[x][y]=0;
            fill();
        }
        else{
            ksm(t-last);
            ans=ans*ret;
            last=t;
            ok[x][y]=1;
            fill();
        }
    }

}

猜你喜欢

转载自www.cnblogs.com/yoyoball/p/9384229.html