ABC450E 题解
出题人,是我赢了。
不,做题人,是我赢了。你把 \(s_{i-1}\) 和 \(s_{i-2}\) 看反了。不然样例的最后一行你为什么输出 \(0\) 呢?
关于下面一些符号的声明:
下文中:
- 当 \(s\) 为字符串时,\(\left| s \right|\) 表示 \(s\) 的长度。
- 当 \(a,b\) 均为字符串时,\(a+b\) 表示将 \(a\) 和 \(b\) 按顺序拼接。
- \(fib_i\) 表示第 \(i\) 个斐波那契数。斐波那契数的计算公式如下:\(fib_i=fib_{i-1}+fib_{i-2}\)。特别的,\(fib_1=fib_2=1\)。
我们不难发现,当 \(\left| X \right|=\left| Y \right|=1\) 时,\(\left| s_i \right|=fib_i\)。这意味着 \(\left| s_{10^{18}} \right|\) 是一个天文数字,所以我们只取它有用的前缀即可。
观察式子:\(s_i=s_{i-1}+s_{i-2}\),这意味着 \(s_{i-1}\) 是 \(s_i\) 的前缀。同理,\(s_{i-2}\) 是 \(s_{i-1}\) 的前缀,所以 \(s_{i-2}\) 是 \(s_i\) 的前缀。同理,\(s_{k}\)(其中 \(1\le k\le i\))是 \(s_i\) 的前缀。通过计算可知第一个 \(\ge 10^{18}\) 的斐波那契数是 \(fib_{88}\),所以我们只取 \(s_{88}\) 这一个有用的前缀即可。
然后我们要实现查找前 \(x\) 个字符中的某字符的数量。我们可以递推计算出 \(s_i\) 中的某字符的数量。查询时我们递归查询 \(x\) 在 \(s_i\) 的哪一部分(前半部分 \(s_{i-1}\) 和后半部分 \(s_{i-2}\)),同时计算出前 \(x\) 个字符中的某字符的数量。
另外理论上应该是要开 __int128 的,但听说不用?
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF=1e18;
__int128 g[26][91];
__int128 f[91];
int st[26];
string s,t;
__int128 cnts[26][10005],cntt[26][10005];
int n;
__int128 sum(int val,int x,int pos){
if(x==1) return cnts[val][pos];
if(x==2) return cntt[val][pos];
if(pos>f[x-1]) return g[val][x-1]+sum(val,x-2,pos-f[x-1]);
else return sum(val,x-1,pos);
}
void Writing(__int128 x){
if(x==0) return;
__int128 S=x/10;
int T=x%10;
Writing(S);
cout<<T;
}
void Write(__int128 x){
if(x==0) cout<<0;
else Writing(x);
}
void man(){
int l,r,d;
char c;
cin>>l>>r>>c;
// if(l==INF&&r==INF){cout<<"1\n";return;}
d=c-'a';
Write(sum(d,n,r)-sum(d,n,l-1));
cout<<'\n';
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>s>>t;
f[1]=s.size();f[2]=t.size();
for(int i=0;s[i];i++){
st[s[i]-'a']++;
for(int j=0;j<26;j++){
cnts[j][i+1]=cnts[j][i];
}
cnts[s[i]-'a'][i+1]++;
}
for(int i=0;i<26;i++){
g[i][1]=st[i];
}
memset(st,0,sizeof st);
for(int i=0;t[i];i++){
st[t[i]-'a']++;
for(int j=0;j<26;j++){
cntt[j][i+1]=cntt[j][i];
}
cntt[t[i]-'a'][i+1]++;
}
for(int i=0;i<26;i++){
g[i][2]=st[i];
}
n=3;
for(int i=3;n<=90;i++,n++){
f[i]=f[i-1]+f[i-2];
for(int j=0;j<26;j++){
g[j][i]=g[j][i-1]+g[j][i-2];
}
if(f[i]>INF) break;
}
int T;cin>>T;
while(T--) man();
return 0;
}

浙公网安备 33010602011771号