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:最后别忘了取模。。。

 

原文地址:https://www.cnblogs.com/qiucz/p/5005390.html