[hdu 5351] MZL's Border


题目链接,我怎么知道题目的标题是什么意思?




题目大意:

定义字符串 s1=a s2=b si=si1+si2  (i3)

同时定义一个字符串 s 的权值为一个最大的 i<|s| 满足 s 长度为 i 的前缀等于长度为 i 的后缀。

比如字符串 aba 的权值就是 1 abab 的权值就是 2 aaaa 的权值就是 3

sn 的前 m 个字符组成的字符串的权值,输出权值取模 258280327 的结果。


首先很显然的一点是, si 包含 si1  (i3)

那么我们考虑 n3 的情况, 设 fi 表示 sn 的前 i 个字符组成的字符串的权值

然后用 KMP 求出 next 数组得到 {fi}  (n=19)

{fi}={0,0,1,1,2,3,2,3,4,5,6,4,5,6,7,8,9,10,11}

将连续的数字分成一段:

0   0 1   1 2 3   2 3 4 5 6   4 5 6 7 8 9 10 11



分成的段的长度分别为 1,2,3,5,8 ,起始值分别为 0,0,1,2,4

可以发现,每一段长度都是 fibi+1 ,起始值都是 fibi1 ( fibi 为斐波拉契数列 )



大胆猜想,小心假设, 从不证明

与暴力对拍之后发现这个规律是对的。

考虑 next[] 数组的构造即可证明这个结论。

根据这个规律可以 O(n) 求出答案,然后就做完了


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
    return;
}
template<class Num>void write(Num x)
{
    if(!x) {putchar('0');return;}
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    while(sl) putchar(s[--sl]);
}
const int maxn = 1000, maxL = 400, Base = 10, Mod = 258280327;
int n;

struct BigNum
{
    int len, num[maxL]; 

    void read()
    {
        static char s[maxL];
        scanf("%s", s + 1);
        len = strlen(s + 1);
        for(int i = len; i >= 1; i--)
            num[i] = s[len + 1 - i] - '0';
    }
    void write()
    {
        if(!len)
        {
            putchar('0');
            return;
        }
        for(int i = len; i >= 1; i--)
            putchar(num[i] + '0');
    }

}m, F[maxn + 5], empty, one, two;

BigNum operator + (const BigNum &a,const BigNum &b)
{
    BigNum c = empty;
    c.len = std::max(a.len, b.len);
    for(int i = 1; i <= c.len; i++)
        c.num[i] = a.num[i] + b.num[i];
    for(int i = 1; i <= c.len; i++)
    {
        c.num[i + 1] += c.num[i] / Base;
        c.num[i] %= Base;
    }
    while(c.num[c.len + 1])
    {
        ++c.len;
        c.num[c.len + 1] += c.num[c.len] / Base;
        c.num[c.len] %= Base;
    }
    return c;
}
BigNum operator - (const BigNum &a,const BigNum &b)
{
    BigNum c = empty;
    for(int i = 1; i <= a.len; i++)
        c.num[i] = a.num[i] - b.num[i];
    for(int i = 1; i <= a.len; i++)
    {
        if(c.num[i] < 0)
        {
            c.num[i + 1] --;
            c.num[i] += Base;
        }
    }
    c.len = 0;
    for(int i = a.len; i >= 1; i --)
    {
        if(c.num[i])
        {
            c.len = i;
            break;
        }
    }
    return c;
}
bool operator > (const BigNum &a,const BigNum &b)
{
    if(a.len != b.len) return a.len > b.len;
    for(int i = a.len; i >= 1; i--)
    {
        if(a.num[i] != b.num[i])
            return a.num[i] > b.num[i];
    }
    return false;
}
int operator %(const BigNum &a,int mod)
{
    int r = 0;
    for(int i = a.len; i >= 1; i--)
        r = ((long long)r * Base + a.num[i])%Mod;
    return r;
}

void prework()
{
    one.num[1] = one.len = 1;
    two.num[1] = 2, two.len = 1;

    F[1] = F[2] = one;
    for(int i = 3; i <= maxn; i++)
        F[i] = F[i - 1] + F[i - 2];
}
void init()
{
    read(n), m.read();
}
void solve()
{
    for(int i = 2; i <= n; i++)
    {
        if(m > F[i])
            m = m - F[i];
        else
        {
            write((F[i - 1] + m - two)%Mod);
            puts("");
            return;
        }
    }
}

int main()
{
    int T;

    read(T);
    prework();

    while(T--) init(), solve();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值