• Luogu P5307 [COCI2019] Mobitel


    题意

    有一个 (r imes c) 的矩阵 (a),矩阵的每个位置都有一个正整数,求从左上角走到右下角并且满足路径上数字乘积之和大于 (n) 的方案数。

    ( exttt{Data Range:}1leq r,cleq 300,1leq nleq 10^6)

    题解

    本人的本命题居然是个 DP + 整除分块呢。

    草哦为什么这个题目名字叫手机啊我怎么看了半天没有看出与手机的任何关联呢

    首先考虑一个非常 naive 的 DP,设 (f_{i,j,k}) 表示在 ((i,j)) 位置,已经走过的路径乘积之和为 (k) 的方案数,那这个东西很明显由于复杂度上天显得非常不可做。

    于是我们可以换个方向去思考这个问题,设 (f_{i,j,k}) 表示在 ((i,j)) 位置还需要乘上 (k),路径的乘积才能超过 (n),这样子的话转移其实也很好写,但是毕竟状态的数量还是太庞大了,复杂度依旧上天。

    这个时候注意到 (k) 这个维度上的取值很少,根据整除分块的理论只会有 (O(sqrt{n})) 种,所以可以考虑对所有真正有用的值来 DP,这个时候只需要预处理出每一个可能的取值对应哪个块即可做到 (O(rcsqrt{n}))

    注意到这东西空间会超,所以考虑对 (i) 这一位滚一下就好了。同时,代码细节贼多,稍不注意就会挂成狗。这个版本的代码跑的贼慢,看看到时候来卡卡常什么的。

    代码

    #include<bits/stdc++.h>
    #define dv(x,y) ((x)/(y)+!!((x)%(y)))
    using namespace std;
    typedef int ll;
    typedef long long int li;
    const ll MAXN=1e6+51,MOD=1e9+7;
    ll r,c,n,blkc;
    ll x[351][351],d[MAXN],rv[MAXN],f[2][351][2051],blk[2051];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    int main()
    {
        r=read(),c=read(),n=read();
        for(register int i=1;i<=r;i++)
        {
            for(register int j=1;j<=c;j++)
            {
                x[i][j]=read();
            }
        }
        for(register int i=1;i<=n;i++)
        {
            (d[i]=dv(n,i))!=d[i-1]?blk[++blkc]=d[i],rv[d[i]]=blkc:1;
        }
        f[1][1][rv[dv(n,x[1][1])]]=1;
        for(register int i=1;i<=r;i++)
        {
            for(register int j=1;j<=c;j++)
            {
                for(register int k=1;k<=blkc;k++)
                {
                    if(i!=r)
                    {
                        ll &s=f[(i&1)^1][j][rv[dv(blk[k],x[i+1][j])]];
                        s=(s+f[i&1][j][k])%MOD;
                    }
                    if(j!=c)
                    {
                        ll &s=f[i&1][j+1][rv[dv(blk[k],x[i][j+1])]];
                        s=(s+f[i&1][j][k])%MOD;
                    }
                    (i!=r||j!=c||k!=blkc)?f[i&1][j][k]=0:1;
                }
            }
        }
        printf("%d
    ",f[r&1][c][blkc]);
    }
    
  • 相关阅读:
    C#利用反射动态调用类及方法
    系统程序监控软件
    SQL server 2008 安装和远程访问的问题
    sql server 创建临时表
    IIS 时间问题
    windows 2008 安装 sql server 2008
    sql server xml nodes 的使用
    Window 7sp1 安装vs2010 sp1 打开xaml文件崩溃
    CSS资源网址
    Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel, Version=3.0.0.0
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13887837.html
Copyright © 2020-2023  润新知