• HDU 5351 MZL's Border (多校联合第5场1009)


    题意:设一个斐波那契串序列,F1=b, F2=a, ..., Fn=Fn-1Fn-2。一个串的LBoardm意思是:取此串的长为m的前缀作为子串,则此子串自身的前后缀最长匹配即为原串的LBoardm。现给出n和m,求斐波那契串Fn的LBoardm。(不知道讲清楚没有。。题意就是这么绕。。)

     

     

    分析:鉴于题意这么BT,过的人又这么多,怀疑是打表找规律。遂写了个暴力CPP程序跑了一下:

     1 // Test Successd!
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 
     5 const int N = 110000;
     6 int next[N], extend[N];
     7 int len[20];
     8 string f[20];
     9 void kmp_pre(string x,int m,int next[])
    10 {
    11     int i,j;
    12     j=next[0]=-1;
    13     i=0;
    14     while(i<m)
    15     {
    16         while(-1!=j && x[i]!=x[j])j=next[j];
    17         next[++i]=++j;
    18     }
    19 }
    20 
    21 int main()
    22 {
    23     f[1] = "b", f[2] = "a";
    24     len[1] = len[2] = 1;
    25     for(int i = 3; i <= 10; ++i)
    26     {
    27         f[i] = f[i-1] + f[i-2];
    28         cout << "?? " << f[i] << endl;
    29         len[i] = len[i-1] + len[i-2];
    30         for(int j = 1; j <= len[i]; ++j)
    31         {
    32             string tmp = f[i].substr(0, j);
    33             kmp_pre(tmp, j, next);
    34             cout << i << " " << j << " " << next[j] << endl;
    35         }
    36     }
    37     return 0;
    38 }
    View Code

    跑完之后果然规律出来了。。。

    结果实际上与n无关,只和m有关,当m依次取1~1000时,对应的结果序列为:(0)(0)(1)(1)(2,3)(2,3)(4,5,6)(4,5,6)(7,8,9,10,11)(7,8,9,10,11)....

    序列分为若干组,每组元素的个数成斐波那契数列,且重复两次。不看重复,所有元素依次递增。要求的第m项是几?

    假设第m项落在第k组里,则有不等式:2*(F1+F2+..+Fk-1)< m <= 2*(F1+F2+..+Fk)成立,可以预处理Fn的前缀和,然后O(n)扫过去求出k。

    然后看它在该组里的第几项。设不等式左右边界分别为L和R,则m在该组内的偏移量为m-L。

    但是!

    每组是重复两次的,所以若偏移量m-L>Fk,则偏移量应该再减去Fk,所以最终偏移量为 (m-L>Fk)?(m-L-Fk):(m-L)

    鉴于数据太大,上java大数类。。。

     1 // AC 358ms 13640k 1330B
     2 // 2015-11-29 20:04 @qiucz
     3 import java.io.*;
     4 import java.util.*;
     5 import java.math.*;
     6 
     7 public class Main
     8 {
     9     public static void main(String[] args) 
    10     {
    11         BigInteger[] f = new BigInteger[1100];
    12         BigInteger[] sum = new BigInteger[1100];
    13         f[1] = f[2] = BigInteger.ONE;
    14         sum[1] = BigInteger.ONE;
    15         sum[2] = BigInteger.valueOf(2);
    16         BigInteger MD = BigInteger.valueOf(258280327);
    17         for(int i = 3; i <= 1010; ++i)
    18         {
    19         f[i] = f[i-1].add(f[i-2]);//.mod(MD);
    20         sum[i] = sum[i-1].add(f[i]);//.mod(MD);
    21         //System.out.println(i + " " + f[i] + " " + sum[i]);//
    22         }
    23 
    24         Scanner cin = new Scanner(System.in);
    25         int T = cin.nextInt();
    26         while(T > 0)
    27         {
    28         BigInteger n = cin.nextBigInteger();
    29         BigInteger m = cin.nextBigInteger();
    30         if(m.compareTo(BigInteger.valueOf(2)) <= 0)
    31         {
    32         System.out.println("0");
    33         continue;
    34         }
    35         //System.out.println(n + " " + m);//
    36         //n = n.mod(MD); m = m.mod(MD);
    37         int i = 1;
    38         while(sum[i].multiply(BigInteger.valueOf(2)).compareTo(m) < 0) ++i;
    39         //System.out.println(i);//
    40         BigInteger d = m.subtract(sum[i-1].multiply(BigInteger.valueOf(2)));//.mod(MD)
    41         if(d.compareTo(BigInteger.ZERO) < 0) d.add(MD);
    42         if(d.compareTo(f[i]) > 0) d = d.subtract(f[i]);
    43         BigInteger ans = sum[i-1].subtract(BigInteger.ONE).add(d).mod(MD);
    44         System.out.println(ans);
    45         --T;
    46         }
    47     }
    48 }
    49 
    50 /*
    51 100
    52 1000 258280326
    53 1000 258280327
    54 */
    55 
    56 /*
    57 155946171
    58 155946172
    59 */
    View Code

    PS:最后别忘了取模。。。

     

  • 相关阅读:
    二叉树前、中、后遍历
    程序员节宜冒泡
    HashMap源码分析
    Stack源码解析
    逆袭之旅DAY24.XIA.二重进阶、双色球
    逆袭之旅DAY24.XIA.数组练习
    LY.JAVA面向对象编程.内部类
    LY.JAVA面向对象编程.修饰符
    LY.JAVA面向对象编程.包的概述、导包
    XIA.人机猜拳
  • 原文地址:https://www.cnblogs.com/qiucz/p/5005390.html
Copyright © 2020-2023  润新知