Rock Is Push (CF 1246C/1247E) 棋盘类dp

区域赛前补道cf 顺便测下魔改快读板子
题目就是 在baba is you游戏中 baba在左上角,旗子在右下角,中间有可以push的石头,只能向右或下走,求获胜方案数
样例3解释图片:https://assets.codeforces.com/rounds/1225/index.html
玩的真的细这都能搞出来
考虑dp,将向右和向下分别记为两种状态,对每一个状态,能移动到的格子都与当前方向上剩余的石头个数有关系,有多少个石头就代表行末/列末有多少个格子不可达。
对于每一个可达的格子,其侧面方向的方案数都可以加上当前正面方向的方案数,这一步可以使用差分完成,在dp的过程中同时维护好前缀和就可以了。
然后来确定哪一些格子是可达的:用正面方向表示当前面对的方向,侧面方向表示另一个方向,则任意位置i,j的侧面方向剩余的石头个数就是原先状态i,j侧面方向上的石子个数。这部分石子个数就是每行或每列上面的后缀和,可以预先预处理出来。
时间复杂度 O ( n ∗ m ) O(n*m) O(nm),cin 311ms fread 296ms 不过还好fread没改出锅hhh

#include <bits/stdc++.h>
#define rint register int
typedef long long ll;
typedef long long unsigned llu;
using namespace std;
const int N=2e3+5;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1e9+7;
const int bs=31;
const double eps=1e-8;
const ll zzz=1e9;
struct IN {
    inline char gc()
    {
        static const int len=1<<18|1;
        static char buf[len],*s,*t;
        return (s==t)&&(t=(s=buf)+fread(buf,1,len,stdin)),s==t?-1:*s++;
    }

    template <typename TP>
    inline IN & operator >> (TP&x)
    {
        static char c,f;
        c=gc(),f=0;
        for(;!isdigit(c);c=gc())
        {
            if(c==-1)return *this;
            f|=c=='-';
        }
        for(x=0;isdigit(c);c=gc())
            x=(x<<3)+(x<<1)+(c^'0');
        f&&(x=-x);
        return *this;
    }

    inline IN & operator >> (char* s)
    {
        char c;
        c=gc();
        while(isspace(c)) c=gc();
        if(c==-1) return *this;
        while(!isspace(c)) *s=0,*s=c,s++,c=gc();
        *s=0;
        return *this;
    }
} io;
char c[N][N];
int line[N][N],col[N][N];
ll cf[N][N][5];
int main()
{
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
#endif

    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    int n,m;
    io>>n>>m;
    if(n==1&&m==1)
    {
        cout<<1<<endl;
        return 0;
    }
    for(int i=1;i<=n;i++)
        io>>&c[i][1];
    for(int i=n;i>=1;i--)
        for(int j=m;j>=1;j--)
        {
            line[i][j]=line[i][j+1]+(c[i][j+1]=='R');
            col[i][j]=col[i+1][j]+(c[i+1][j]=='R');
        }
    cf[1][1][1]=cf[1][1][0]=1,cf[1][2][0]=cf[2][1][1]=-1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cf[i][j][0]=(cf[i][j][0]+cf[i][j-1][0])%mod;
            cf[i][j][1]=(cf[i][j][1]+cf[i-1][j][1])%mod;
            cf[i][j+1][0]=(cf[i][j+1][0]+cf[i][j][1])%mod;
            cf[i][m+1-line[i][j]][0]=(cf[i][m+1-line[i][j]][0]-cf[i][j][1]+mod)%mod;
            cf[i+1][j][1]=(cf[i+1][j][1]+cf[i][j][0])%mod;
            cf[n+1-col[i][j]][j][1]=(cf[n+1-col[i][j]][j][1]-cf[i][j][0]+mod)%mod;
        }
    cout<<(cf[n][m][0]+cf[n][m][1])%mod<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值