題面
原題連結
思路
先從特殊性質入手,考慮 \(s=0\) 的情況。
不難發現,路徑是已經確定的,那麼我們可以考慮手搓幾步。
可以看出似乎是兩個二進位制位繫結在一起變化的,為了方便,我們不妨將其變作四進位制。
規律已經很顯然了,每一個四進位制位都在做 \(0\rightarrow1\rightarrow3\rightarrow2\rightarrow0\)的重複運動。
接下來,我們考慮第二個特殊性質:如何得出第一次到達某個點的步數?(仍然假設從 \(0\) 開始)
不難發現,我們可以單獨計算每一個四進位制位對於結果的貢獻。
假如說當前位是第 \(k\) 位(從 \(1\) 開始編號),值為 \(a\),用 \(f(a)\) 表示 \(a\) 值出現的序號(根據重複運動的先後順序),那麼這一位的貢獻 \(x\) 為:
整個數的步數就是每一位的貢獻之和。上述公式容易理解,不做具體解釋。
接下來,我們考慮多次到達的情況。
從本質來說,只有 \(0\) 能夠被到達多次,而其他數字都只能到達一次。所以,重複到達的次數,必然是由這個數中的 \(0\) 決定的。
每一次重複,當且僅當這一位完成了一次迴圈,也就是從 \(0\) 到 \(0\) 的過程,並且此時其他位都沒有發生改變。我們注意到當這一位回到 \(0\) 時,所有比它低的位上都只能是 \(0\),因為當它剛好變回 \(0\),比它低的位就全為 \(0\),而它如果再走一步,就必須變化比它高的一位,這與此時其他位都沒有發生改變的要求不符。
所以,重複到達的次數,與這個數末尾連續的 \(0\) 個數有關。因為每一位 \(0\) 都可以貢獻一次重複,那麼最大經過次數就是 \(z+1\),其中 \(z\) 表示末尾連續 \(0\) 個數。注意到,\(0\) 是沒有次數上限的。
下面考慮總步數,我們可以分成第一次到達的步數以及重複的步數。第一次到達的步數就是 \(k=1\),那麼考慮重複所需要的步數。
事實上,一次重複就是一次迴圈,每一位 \(0\) 都能貢獻一次重複,並且是從低位到高位貢獻。並且我們知道每一位進行一次迴圈的步數,那麼我們就可以知道重複 \(k\) 次一共需要的步數。公式化地表示為:
至此,我們已經解決了特殊性質 \(s=0\) 的情況。那麼我們考慮 \(s\ne 0\) 的情況。
不難發現,從 \(s\) 走到 \(t\) 等價於從 \(0\) 走到 \(s\oplus t\)。然後就沒有然後了。
設 \(len_4\) 表示對應數的四進位制位數,\(x_i(S)\)表示 \(S\) 在四進位制下的第 \(i\) 位(從 \(1\) 開始編號),答案即為:
實現
並沒有什麼需要特別講的細節問題。
程式碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const ll mod=1e9+7;
const ll inv3=333333336;
string s,t;int k;
int xo[N],so[N>>1];
ll ans;
int tim[4]={0,1,3,2};
ll qpow(ll a,int b){
ll res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll sk(ll k){
return (qpow(4,k+1)-1+mod)%mod*inv3%mod;
}
void solve(){
ans=0;
cin>>s>>t>>k;
reverse(s.begin(),s.end());
reverse(t.begin(),t.end());
int n=max(s.size(),t.size());
for(int i=0;i<n;i++){
if(i>=s.size())xo[i]=t[i]-'0';
else if(i>=t.size())xo[i]=s[i]-'0';
else xo[i]=(s[i]-'0')^(t[i]-'0');
so[i>>1]=0;
}
int m=-1,zr=-1;
for(int i=0;i<n;i++){
if(i&1)(so[i>>1]|=(xo[i]<<1));
else (so[i>>1]|=xo[i]);
if(so[i>>1]>0){
m=(i>>1);
if(zr==-1)zr=(i>>1);
}
}
m++;
if(m==0){
cout<<sk(k-1)-1<<"\n";
return;
}
if(k>zr+1){
cout<<-1<<"\n";
return;
}
for(int i=0;i<m;i++){
ans=(ans+sk(i)*tim[so[i]]%mod)%mod;
}
ans=(ans+sk(k-1)-1+mod)%mod;
cout<<ans<<"\n";
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t;cin>>t;
while(t--)solve();
return 0;
}