zoukankan      html  css  js  c++  java
  • 【XR-1】分块

    题目link:https://www.luogu.com.cn/problem/P5343


    Part1:

    首先这道题能够想到一个比较显然的 $dp$ 。

    设 $dp[i]$ 表示长度为 $i$ 的序列有几种分块方式。

    那么容易的出转移方程: $dp[i]$ $=$ $∑$ $dp[i$ $-$ $p[j]]$ $(1$ $≤$ $j$ $≤$ $l)$ ,其中 $l$ 为相同长度的块数, $p[j]$ 表示第 $j$ 个相同长度的块。

    这样便可以 $O(n)$ 求出答案,可以通过 $60$$\%$ 的数据,但是 $100$$\%$ 的数据中 $0$ $≤$ $n$ $≤$ $10^{18}$ 。


    Part2:

    考虑优化,显然这个递推式是一个常系数线性递推,而这个 $l$ 的大小最大为 $100$ ,因此可以用矩阵快速幂优化。

    因此只需要预处理出前 $100$ 的 $dp$ 值,之后构造初始向量和转移矩阵就可以了。


    时间复杂度 $O($$x^3$ $*$ $log$ $k)$。


    Code:

      1 #include <cstdio>
      2 #include <algorithm>
      3 
      4 typedef long long LL;
      5 
      6 const int MAXN = 100;
      7 const LL MOD = 1e9 + 7;
      8 
      9 LL n, dp[MAXN + 5];
     10 int pr, nf, prPiece[MAXN + 5], nfPiece[MAXN + 5];
     11 int len, piece[MAXN + 5], x;
     12 
     13 struct Mat {
     14 
     15     int N, M;
     16     LL arr[MAXN + 5][MAXN + 5];
     17 
     18     Mat() {}
     19     Mat(int _N, int _M, LL val = 0ll) {
     20         N = _N, M = _M;
     21         for(int i = 1; i <= N; ++i) {
     22             for(int j = 1; j <= M; ++j) {
     23                 arr[i][j] = (i == j) ? val : 0ll;
     24             }
     25         }
     26     }
     27 
     28     // void print() {
     29     //     for(int i = 1; i <= N; ++i) {
     30     //         for(int j = 1; j <= M; ++j) {
     31     //             printf("%lld%c", arr[i][j], j == M ? '
    ' : ' ');
     32     //         }
     33     //     }
     34     //     puts("");
     35     // }
     36 
     37 };
     38 
     39 Mat operator* (const Mat &A, const Mat &B) {
     40 
     41     Mat res(A.N, B.M);
     42 
     43     for(int i = 1; i <= res.N; ++i) {
     44         for(int j = 1; j <= res.M; ++j) {
     45             for(int k = 1; k <= A.M; ++k) {
     46                 res.arr[i][j] += (A.arr[i][k] * B.arr[k][j]) % MOD;
     47                 res.arr[i][j] %= MOD;
     48             }
     49         }
     50     }
     51 
     52     return res;
     53 }
     54 
     55 Mat qpow(Mat A, LL k) {
     56 
     57     Mat res(A.N, A.M, 1);
     58 
     59     for(; k; k >>= 1) {
     60         if(k & 1) res = res * A;
     61         A = A * A;
     62     }
     63 
     64     return res;
     65 }
     66 
     67 int max(int a, int b) {
     68     return a > b ? a : b;
     69 }
     70 
     71 int main() {
     72 
     73     scanf("%lld", &n);
     74 
     75     scanf("%d", &pr);
     76     for(int i = 1; i <= pr; ++i) {
     77         scanf("%d", &prPiece[i]);
     78     }
     79 
     80     scanf("%d", &nf);
     81     for(int i = 1; i <= nf; ++i) {
     82         scanf("%d", &nfPiece[i]);
     83     }
     84 
     85     std::sort(prPiece + 1, prPiece + pr + 1);
     86     std::sort(nfPiece + 1, nfPiece + nf + 1);
     87     int ptPr = 1, ptNf = 1;
     88     while(ptPr <= pr && ptNf <= nf) {
     89         if(prPiece[ptPr] < nfPiece[ptNf]) {
     90             ++ptPr;
     91         }
     92         else if(prPiece[ptPr] > nfPiece[ptNf]) {
     93             ++ptNf;
     94         }
     95         else {
     96             if(prPiece[ptPr] != prPiece[ptPr - 1] && nfPiece[ptNf] != nfPiece[ptNf - 1]) {
     97                 piece[++len] = prPiece[ptPr];
     98             }
     99             ++ptPr, ++ptNf;
    100         }
    101     }
    102 
    103     for(int i = 1; i <= len; ++i) {
    104         x = max(x, piece[i]);
    105     }
    106 
    107     Mat fac(x, x), vec(1, x);
    108     dp[0] = 1ll;
    109     for(int i = 1; i <= x; ++i) {
    110         for(int j = 1; j <= len; ++j) {
    111             if(i - piece[j] < 0) break;
    112             dp[i] += dp[i - piece[j]];
    113             dp[i] %= MOD;
    114         }
    115     }
    116 
    117     for(int i = 1; i <= x; ++i) {
    118         vec.arr[1][i] = dp[x - i + 1];
    119     }
    120 
    121     for(int i = 1; i <= len; ++i) {
    122         fac.arr[piece[i]][1] = 1ll;
    123     }
    124 
    125     for(int i = 1; i <= fac.N; ++i) {
    126         for(int j = 2; j <= fac.M; ++j) {
    127             fac.arr[i][j] = (i == j - 1) ? 1ll : 0ll;
    128         }
    129     }
    130 
    131     if(n <= x) {
    132         printf("%lld
    ", dp[n]);
    133     }
    134     else {
    135         printf("%lld
    ", (vec * qpow(fac, n - x)).arr[1][1]);
    136     }
    137 
    138     return 0;
    139 }
  • 相关阅读:
    Git与GitHub(利用git上传本地文件到GitHub上面)
    PHP之上传文件upload.php
    PHP之数据库连接配置文件
    MUI 之picker,dialog,a标签——刷新页面问题(保留picker选中的数据)
    MUI自定义select down 下拉框
    Google按ESC退出全屏(带iframe网站)解决问题方案
    提高开发效率 -> 图片
    sublime text
    头脑风暴
    http://www.uupoop.com/ps/
  • 原文地址:https://www.cnblogs.com/qqq1112/p/15060499.html
Copyright © 2011-2022 走看看