zoukankan      html  css  js  c++  java
  • Codeforces Gym101205D:Fibonacci Words(KMP+递推)

    Gym 101205D

    题意:f[0] = "0", f[1] = "1",接下来f[i] = f[i-1] + f[i-2],相当于字符串拼接。然后给出一个n和一个串s,问f[n]里面有多少个s。

    思路:在int范围内的f[n]是n=31的时候,但是匹配的s的长度只有1e5,这时候n=27刚好大于它,因此可以先求解出n<=27的串的情况,然后由这些串来得到n>27的时候的情况。

    比赛的时候想着递归算,结果爆栈。

    看别人的代码之后我的理解是这样的:

    (1)当n<=28的时候,可以直接kmp算。

    (2)当n>28的时候,我们可以得到下面的递推式:(ans[i]表示f[i]里面有多少个s.可以先kmp求出ans[i](25 <= i <= 28) ).

    先定义odd = ans[27] - ans[26] - ans[25](即得到s[27]由s[26]和s[25]拼接起来的时候能多得到的答案).

    even = ans[28] - ans[27] - ans[26](即得到s[28]由s[27]和s[26]拼接起来的时候能多得到的答案).

    因为len(s[27])和len(s[28])一定大于匹配的s,因此不用每次都暴力求解拼接起来的时候能多得到的答案,只需要在i为奇数的时候加上odd,i为偶数的时候加上even就可以得到拼接起来能多得到的答案了。

    一开始以为奇偶是一样的情况,但是WA8之后问别人才知道是不一样的。

    找6号串和找5号串的情况,可以发现6号串可以出现在8号串连接处而不能出现在7和9号串连接处。5号串能出现在7和9号的连接处但是不能出现在8号串的连接处,所以应当是分开考虑的。

    这就是WF最水的题目之一...

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define N 105
     4 #define M 100010
     5 typedef long long LL;
     6 int nxt[M], len[N], sz;
     7 string str, s[N];
     8 LL ans[N];
     9 
    10 void Make_Next() {
    11     int i, j; j = nxt[0] = -1; i = 0;
    12     while(i < sz) {
    13         while(j != -1 && str[i] != str[j]) j = nxt[j];
    14         if(str[++i] == str[++j]) nxt[i] = nxt[j];
    15         else nxt[i] = j;
    16     }
    17 }
    18 
    19 LL Kmp(int id) {
    20     int i = 0, j = 0, ans = 0;
    21     while(i < len[id]) {
    22         while(-1 != j && s[id][i] != str[j]) j = nxt[j];
    23         i++; j++;
    24         if(j >= sz) { ans++; j = nxt[j]; }
    25     }
    26     return ans;
    27 }
    28 
    29 int main() {
    30     int n, cas = 1;
    31     s[0] = "0", s[1] = "1"; len[0] = len[1] = 1;
    32     for(int i = 2; i <= 28; i++) s[i] = s[i-1] + s[i-2], len[i] = len[i-1] + len[i-2];
    33     while(~scanf("%d", &n)) {
    34         cin >> str;
    35         sz = str.length(); Make_Next();
    36         if(n <= 28) { printf("Case %d: %lld
    ", cas++, Kmp(n)); continue; }
    37         for(int i = 25; i <= 28; i++) ans[i] = Kmp(i);
    38         LL odd = ans[27] - ans[26] - ans[25], eve = ans[28] - ans[27] - ans[26]; // 拼接起来能够得到的贡献
    39         for(int i = 29; i <= n; i++) {
    40             ans[i] = ans[i-1] + ans[i-2];
    41             if(i & 1) ans[i] += odd;
    42             else ans[i] += eve;
    43         }
    44         printf("Case %d: %lld
    ", cas++, ans[n]);
    45     }
    46     return 0;
    47 }
  • 相关阅读:
    在intellij 下用java spring + Mysql + Hibernate 开发的第一个数据库demo
    推荐一个找到一个比较好的spring,java学习教程
    ReactiveCocoa 中signal(operation) then与doNext的区别
    grunt
    Swiper.js wap app 图片滑动效果
    less 路径 写法
    html5 input placeholder 占位符 输入框提示文本
    js 大小写转换
    css 修改选中文字的颜色
    keydown keypress keyup textInput
  • 原文地址:https://www.cnblogs.com/fightfordream/p/6610978.html
Copyright © 2011-2022 走看看