T1

一个网格,每个点有权值,求有多少条路径权值乘积不小于 $n$

$R,C \leq 300, n \leq 10^6$

sol:

暴力 dp 是 $O(R \times C \times n)$ 的

然后发现如果一条路径大于 $n$ ,直接把它设成 $n$ 即可,然后又发现 $\lfloor \frac{n}{i} \rfloor$ 只有 $O(\sqrt{n})$ 种取值,记录一下即可做到 $O(R \times C \times \sqrt{n})$

#include <bits/stdc++.h>
#define Debug(x) cerr << #x << " = " << x << '\n'
#define debug(x) cerr << #x << " = " << x
#define TAB << " "
#define EDL << "\n"
#define LL long long
#define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -f;
    for(; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
    return x * f;
}
const int mod = 1e9 + 7, maxn = 510;
int n, m, q, stk[15010], top, bl[1005010];
int a[maxn][maxn], dp[2][maxn][15010];
inline void mo(int &x) { if(x >= mod) x -= mod; if(x < 0) x += mod; }
int main() {
    //freopen("mobitel.in","r",stdin);
    //freopen("mobitel.out","w",stdout);
    n = read(), m = read(), q = read(); q--;
    rep(i, 1, n) rep(j, 1, m) a[i][j] = read();
    for(int l = 1, r; l <= q; l = r + 1) r = q / (q / l), stk[++top] = q / r, bl[q / r] = top;
//    Debug(top);
    stk[++top] = 0, bl[0] = top;
    int now = q;
    rep(i, 1, m) {
        now /= a[1][i], dp[1][i][bl[now]] = 1;
        //debug(i) TAB; debug(now) TAB; debug(a[1][i]) EDL;
    }
    //Debug(now);
    int cur = 1, last = 0;
    rep(i, 2, n) {
        last = cur, cur = cur ^ 1;
        memset(dp[cur], 0, sizeof(dp[cur]));
        //Debug(cur);
        rep(j, 1, m) {
        //    assert(a[i][j] != 0);
            rep(k, 1, top) {
                //assert(a[i][j] != 0);
                dp[cur][j][bl[stk[k] / a[i][j]]] += dp[last][j][k];
                mo(dp[cur][j][bl[stk[k] / a[i][j]]]);
                if(j != m) {
                    dp[cur][j + 1][bl[stk[k] / a[i][j + 1]]] += dp[cur][j][k];
                    mo(dp[cur][j + 1][bl[stk[k] / a[i][j + 1]]]);
                }
                //debug(i) TAB; debug(j) TAB; debug(k) EDL;
            }
        }
    } cout << dp[cur][m][top] << endl;
}
View Code

相关文章: