看到这题讨论版里有说用公式的有说用循环节的,但是个人觉得这两种方法都不靠谱,比赛场上做这种题能直接推出公式需要很强数学功底,而循环节的方法如果循环节比较大就不太好发现了。这种已知通项公式的题还是用矩阵快速幂比较通用,但同是矩阵快速幂,对于这题,也有很大的差异;

注:memmove这个函数可能不太常见,但还是比较好用的,可以用较低的时间复杂度完成数组的拷贝

  • 方法一

    Time Limit Exceeded 2802 1000MS 1348K 1734 B G++
    #include "bits/stdc++.h"
    using namespace std;
    const int MOD = ;
    /*
    {f(n - 1), f(n - 2), n ^ 3, (n - 1) ^ 3, n ^ 2, n, 1}
    乘MAT得到
    {f(n), f(n - 1), (n + 1) ^ 3, n ^ 3, (n + 1) ^ 2, n + 1, 1}
    */
    const int MAT[][] = {
    {, , , -, , , },
    {, , , , , , },
    {, , , , , , },
    {, , , , , , },
    {, , , , , , },
    {, , , , , , },
    {, , , , , , }
    };
    const int TABLE[] = {, , , , , , };
    struct Mat {
    int mat[][];
    Mat() {
    memset(mat, , sizeof(mat));
    }
    friend Mat operator * (Mat n, Mat m) {
    Mat res;
    for (int k = ; k < ; k++)
    for (int i = ; i < ; i++)
    for (int j = ; j < ; j++) {
    res.mat[i][j] += n.mat[i][k] * m.mat[k][j];
    // 因为当n >=0 时 (n + 1) ^ 3 一定大于 n ^ 3,所以要保证结果是正数;
    res.mat[i][j] = (res.mat[i][j] % MOD + MOD) % MOD;
    }
    return res;
    }
    } m;
    Mat mat_pow(Mat n, int k) {
    Mat res;
    for (int i = ; i < ; i++) {
    res.mat[i][i] = ;
    }
    while (k) {
    if (k & ) {
    res = res * n;
    }
    n = n * n;
    k >>= ;
    }
    return res;
    }
    int main() {
    int n;
    while (scanf("%d", &n) && n) {
    if (n == ) {
    puts("");
    continue;
    }
    if (n == ) {
    puts("");
    continue;
    }
    memmove(m.mat, MAT, sizeof(m.mat));
    m = mat_pow(m, n - );
    int res = ;
    for (int i = ; i < ; i++) {
    res = (res + m.mat[][i] * TABLE[i]) % MOD;
    }
    printf("%d\n", res);
    }
    return ;
    }

    这是拿到题直接把递推式拿来套的解法,7层矩阵,超时。于是想到n ^ 3  - (n - 1) ^ 3 = (n - 1) ^ 3 + 3 * (n - 1) ^ 2 + 3 * (n - 1) + 1 - (n - 1) ^ 3;可以抵消(n  - 1) ^ 3;

  • 方法二

    Accepted 2802 889MS 1384K 1462 B G++
    #include "bits/stdc++.h"
    using namespace std;
    const int MOD = ;
    /*
    {f(n - 1), f(n - 2), n ^ 2, n, 1}
    乘MAT得到
    {f(n), f(n - 1), (n + 1) ^ 2, n + 1, 1}
    */
    const int MAT[][] = {
    {, , , , },
    {, , , , },
    {, , , , },
    {, , , , },
    {, , , , }
    };
    const int TABLE[] = {, , , , };
    struct Mat {
    int mat[][];
    Mat() {
    memset(mat, , sizeof(mat));
    }
    friend Mat operator * (Mat n, Mat m) {
    Mat res;
    for (int k = ; k < ; k++)
    for (int i = ; i < ; i++)
    for (int j = ; j < ; j++)
    res.mat[i][j] = (res.mat[i][j] + n.mat[i][k] * m.mat[k][j]) % MOD;
    return res;
    }
    } m;
    Mat mat_pow(Mat n, int k) {
    Mat res;
    for (int i = ; i < ; i++) {
    res.mat[i][i] = ;
    }
    while (k) {
    if (k & ) {
    res = res * n;
    }
    n = n * n;
    k >>= ;
    }
    return res;
    }
    int main() {
    int n;
    while (scanf("%d", &n) && n) {
    if (n == ) {
    puts("");
    continue;
    }
    if (n == ) {
    puts("");
    continue;
    }
    memmove(m.mat, MAT, sizeof(m.mat));
    m = mat_pow(m, n - );
    int res = ;
    for (int i = ; i < ; i++) {
    res = (res + m.mat[][i] * TABLE[i]) % MOD;
    }
    printf("%d\n", res);
    }
    return ;
    }

    降到5层矩阵之后能AC掉这题了,但是这个矩阵还不是最好的。这个代码的效率还是不高。

  • 方法三
    Accepted 2802 483MS 1392K 1551 B G++
    #include "bits/stdc++.h"
    using namespace std;
    const int MOD = ;
    /*
    {f(n - 2), (n + 1) ^ 2, (n + 1), 1}
    乘MAT得到
    {f(n), (n + 3) ^ 2, n + 3, 1}
    */
    const int MAT[][] = {
    {, , , },
    {, , , },
    {, , , },
    {, , , }
    };
    const int TABLE1[] = {, , , };
    const int TABLE2[] = {, , , };
    struct Mat {
    int mat[][];
    Mat() {
    memset(mat, , sizeof(mat));
    }
    friend Mat operator * (Mat n, Mat m) {
    Mat res;
    for (int k = ; k < ; k++)
    for (int i = ; i < ; i++)
    for (int j = ; j < ; j++)
    res.mat[i][j] = (res.mat[i][j] + n.mat[i][k] * m.mat[k][j]) % MOD;
    return res;
    }
    } m;
    Mat mat_pow(Mat n, int k) {
    Mat res;
    for (int i = ; i < ; i++) {
    res.mat[i][i] = ;
    }
    while (k) {
    if (k & ) {
    res = res * n;
    }
    n = n * n;
    k >>= ;
    }
    return res;
    }
    int main() {
    int n;
    while (scanf("%d", &n) && n) {
    if (n == ) {
    puts("");
    continue;
    }
    if (n == ) {
    puts("");
    continue;
    }
    memmove(m.mat, MAT, sizeof(m.mat));
    m = mat_pow(m, n - >> );
    int res = ;
    /*
    假设重定义两个函数,a(n) = f(2 * n - 1), b(n) = f(2 * n);
    if (n & 1) 求得a((n - 1) >> 1)即为 f(n)
    else 求得b((n - 1) >> 1) 即为f(n)
    */
    if (n & ) {
    for (int i = ; i < ; i++) {
    res = (res + m.mat[][i] * TABLE1[i]) % MOD;
    }
    } else {
    for (int i = ; i < ; i++) {
    res = (res + m.mat[][i] * TABLE2[i]) % MOD;
    }
    }
    printf("%d\n", res);
    }
    return ;
    }

    递推式是从f(n)直接到f(n + 2)的,所以相当于把f拆成两个函数分开讨论,只用4层矩阵就够了。对于矩阵快速幂,4层应该是最少的了。如果还要再快,那就只能采取循环节或公式的方式了。

  • 方法四(来自讨论版,代码省略)
    这题的循环节是4018(正好是MOD的两倍,不知道是不是巧合)。
  • 方法五(来自讨论版,代码省略)
    n为奇数 (n+1)(n+1)(2n-1)/4;
    n为偶数 n*n*(2n+3)/4

HDU-2802-F(N)的更多相关文章

  1. HDU 2802 F(N)(简单题,找循环解)

    题目链接 F(N) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  2. HDU - 2802 F(N) (周期)

    题目链接:HDU 2009-4 Programming Contest 分析:具有一定的周期性——4018处理下就可以A了 Sample Input Sample Output AC代码: #incl ...

  3. HDU 2802 F(N) 数论+打表

    题目大意:f[n]-n^3=f[n-2]-(n-1)^3 (n >=3),f[1]=1,f[2]=7,求f[n]. 题目思路:将n^3移到到等式右边化简的到:f[n]=f[n-2]+3n*(n- ...

  4. 数学--数论--HDU 2802 F(N) 公式推导或矩阵快速幂

    Giving the N, can you tell me the answer of F(N)? Input Each test case contains a single integer N(1 ...

  5. 【数位DP】 HDU 4734 F(x)

    原题直通车:HDU 4734 F(x) 题意:F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1, 求0.....B中F[x]<=F[A ...

  6. HDU 4734 F(x) 2013 ACM/ICPC 成都网络赛

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4734 数位DP. 用dp[i][j][k] 表示第i位用j时f(x)=k的时候的个数,然后需要预处理下小 ...

  7. HDU 4734 - F(x) - [数位DP][memset优化]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 Time Limit: 1000/500 MS (Java/Others) Memory Lim ...

  8. HDU 1937 F - Finding Seats 枚举

    F - Finding Seats Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u S ...

  9. hdu 4734 F(x)(数位dp+优化)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734 题意:我们定义十进制数x的权值为f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2 ...

  10. E - Tunnel Warfare HDU - 1540 F - Hotel G - 约会安排 HDU - 4553 区间合并

    E - Tunnel Warfare HDU - 1540 对这个题目的思考:首先我们已经意识到这个是一个线段树,要利用线段树来解决问题,但是怎么解决呢,这个摧毁和重建的操作都很简单,但是这个查询怎么 ...

随机推荐

  1. 第 10 章 gdb

    一.参考网址 1.linux c编程一站式学习 二.命令列表 1.图1: 2.图2: 3.图3: 三.重点摘抄 1.断点与观测点的区别 我们知道断点是当程序执行到某一代码行时中断,而观察点是当程序访问 ...

  2. Struts 2 的常规配置

    Struts 2 的默认配置文件是struts.xml,该文件应该放在Web应用的类加载路径下,通常就是放在WEB-INF/classes路径下. struts.xml文件的最大作用是配置Action ...

  3. 15)png图片旋转贴图

    1)基本代码展示  还是上一个那个总代码: #include<Windows.h> #include<gdiplus.h>//GDI+的头文件 using namespace ...

  4. 吴裕雄--天生自然深度学习TensorBoard可视化:命名空间

    # 1. 不同的命名空间. import tensorflow as tf with tf.variable_scope("foo"): a = tf.get_variable(& ...

  5. 黑马oracle_day02:04.oracle对象&&05.oracle编程(a)

    01.oracle体系结构 02.oracle的基本操作 03.oracle的查询 04.oracle对象&&05.oracle编程(a) 05.oracle编程(b) 04.orac ...

  6. PAT Advanced 1078 Hashing (25) [Hash ⼆次⽅探查法]

    题目 The task of this problem is simple: insert a sequence of distinct positive integers into a hash t ...

  7. UML-如何进行对象设计?

    之前的章节,学过了OOA,以及交互图+类图.本章主要讲述OOD.OOD就是面向对象设计,那如何进行对象设计? 概览 1.输入制品 注:这些制品并非都必要. 2.活动 1).针对输入的制品,采用什么样的 ...

  8. 进程间数据共享 (multiprocess.Manager)

    进程间数据共享 (multiprocess.Manager) 一.进程之间的数据共享 展望未来,基于消息传递的并发编程是大势所趋 即便是使用线程,推荐做法也是将程序设计为大量独立的线程集合,通过消息队 ...

  9. HDU - 1754 线段树

    #include <algorithm> #include <iostream> #include<sstream> #include<cstring> ...

  10. 01 语言基础+高级:1-7 异常与多线程_day06 【线程、同步】

    day06 [线程.同步] 主要内容 线程 同步 线程状态 一.学习目标 1. 能够描述Java中多线程运行原理 2. 能够使用继承类的方式创建多线程 3. 能够使用实现接口的方式创建多线程 4. 能 ...