abcdeffa's Blog

当局者迷,旁观者清。

0%

GMOJ S4213 【对你的爱深不见底】

Description

有若干个字符串 $s_1$ ~ $s_\infty$,其中 $s_1$ = ‘a‘,$s_2$ = ‘b‘,$s_i = s_{i - 1} + s_{i - 2}$。

定义一个字符串 $S$ 的价值为 $i$ 当且仅当 $i$ 小于 $|S|$ 且 $S[1..i] = S[n - i + 1..n]$,现在给出你 $T$ 组数据,每组数据给出你两个正整数 $n$ 和 $m$,请你对于每组数据求出字符串 $s_n$ 长度为 $m$ 的前缀的价值。

Solution

吉老师的一道有趣的题。

找规律可以发现,如果我们设 $f_i$ 表示斐波那契数列的第 $(i + 1)$ 项,则若 $pos$ 为最小的可以使 $f_{pos} > m + 1$ 的数,则答案为 $(m - f_{pos - 2})$。

证明留作读者练习。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <cstdio>
#include <cstring>
#define mod 258280327LL
#define maxN 1010
char st[710];
int f[maxN][710];
int Ans[710], a[710];
int max (int x, int y)
{
return x > y ? x : y;
}
void work (int x)
{
int A = f[x - 1][0];
int B = f[x - 2][0];
int C = max(A, B);
for(int i = 1;i <= C; i++)
{
f[x][i] = f[x - 1][i] + f[x - 2][i];
}
for(int i = 1;i <= C; i++)
{
if(f[x][i] > 9)
{
f[x][i + 1]++;
if(i + 1 > C)
{
C++;
}
f[x][i] -= 10;
}
}
f[x][0] = C;
}
int main ()
{
f[1][0] = 1;
f[1][1] = 1;
f[2][0] = 1;
f[2][1] = 2;
for(int i = 3;i < maxN; i++)
{
work(i);
}
int T = 0;
int cnt = 0;
scanf("%d", &T);
while(T--)
{
cnt++;
int n = 0;
scanf("%d", &n);
scanf("%s", st + 1);
int A = strlen(st + 1);
for(int i = 1;i <= A; i++)
{
a[i] = st[A - i + 1] - '0';
}
int pos = 0;
a[1]++;
for(int i = 1;i <= A; i++)
{
if(a[i] > 9)
{
a[i + 1]++;
a[i] -= 10;
if(i + 1 > A)
{
A++;
}
}
}
for(int x = 1;x < maxN; x++)
{
int B = f[x][0];
if(A == B)
{
bool flag = false;
for(int i = A;i >= 1; i--)
{
int nowA = a[i];
int nowB = f[x][i];
if(i == 1)
{
if(nowB > nowA)
{
flag = true;
break;
}
}
else
{
if(nowB > nowA)
{
flag = true;
break;
}
else if(nowB < nowA)
{
break;
}
}
}
if(flag)
{
pos = x - 2;
break;
}
}
else if(A < B)
{
pos = x - 2;
break;
}
}
a[1]--;
for(int i = 1;i <= A; i++)
{
if(a[i] < 0)
{
a[i + 1]--;
a[i] += 10;
}
}
while(!a[A] && A >= 2)
{
A--;
}
for(int i = A;i >= 1; i--)
{
Ans[i] = a[i] - f[pos][i];
a[i] = 0;
}
for(int i = 1;i <= A; i++)
{
if(Ans[i] < 0)
{
Ans[i + 1]--;
Ans[i] += 10;
}
}
while(!Ans[A] && A >= 2)
{
A--;
}
long long res = 0;
for(int i = A;i >= 1; i--)
{
res = res * 10LL + Ans[i];
res %= mod;
}
printf("%lld\n", res);
}
return 0;
}