题目链接,我怎么知道题目的标题是什么意思?
题目大意:
定义字符串 s1=a , s2=b , si=si−1+si−2 (i≥3)
同时定义一个字符串
s
的权值为一个最大的
比如字符串
求
首先很显然的一点是, si 包含 si−1 (i≥3)
那么我们考虑 n≥3 的情况, 设 fi 表示 sn 的前 i 个字符组成的字符串的权值
然后用 KMP 求出
{fi}={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 ,起始值都是 fibi−1 ( 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;
}