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;
}
posted @ 2026-03-23 18:14  NiYqaq  阅读(12)  评论(0)    收藏  举报