题意:有一个非空字符串S1只含有字符”a”,”b”。可将Si变为S(i+1),方法是将Si中的a全部变换为b,将b全部变换为a。现在给出了Sn和Sm的长度,分别为L1, L2,并且知道n, m,问是否存在一个合理的S1,如果存在, 求Sk的长度是多少(mod 1e9 + 7)。所有变量在(0, 1e9] 范围内。
解法:设S1中含有n1个a和n2个b(n1 + n2 > 0),不难发现Si的n1和n2满足fibonacci数列性质,Si.n1 = fibo[i - 1] * n1 + fibo[i] * n2,Si.n2 = fibo[i] * n1 + fibo[i+1] * n2;其中n1, n2 是S1中a和b的个数,fibo是fibonacci数列,且fibo[0] = 1, fibo[1] = 0, fibo[i] = fibo[i-2] + fibo[i-1] (i > 1)。。由此,可以得到两个二元一次线性方程a * n1 + b * n2 = c, d * n1 + e * n2 = f,其中 a = fibo[n - 1] + fibo[n],b = fibo[n] + fibo[n + 1],c = fibo[m - 1] + fibo[m], d = fibo[m] + fibo[m + 1], c = L1,f = L2。由此可以解出 n1, n2,那么ans = (fibo[k-1] + fibo[k]) * n1 + (fibo[k] + fibo[k+1]) * n2。。由于k达到了1e9级别,所以解ans用矩阵快速幂来求(fibonacci数满足这个性质)。。这个前提是有解,如果无解,需要判断,判断点很多,首先考虑二元一次方程,可以存在无解,其次考虑n 和 m 给太大可能导致无解,因为L1, L2 只是1e9级别,n 和 m 不可能太大,可以判断如果n , m 有一个超过80,则一定无解,因为这种情况下,L1 , L2不可能不超过1e9。。细节再注意一下。。看代码
My Code
#include<cstdio>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
ll fibo[105];
int getans(ll a, ll b, ll c, ll d, ll e, ll f, ll &x, ll &y){
if(b * d - a * e == 0) return -1;
if((a >= c && b >= c) || (d >= f && e >= f)) return -1;
if((c * d - a * f) % (b * d - a * e) != 0) return -1;
y = (c * d - a * f) / (b * d - a * e);
if((c - b * y) % a != 0) return -1;
x = (c - b * y) / a;
if(x < 0 || y < 0 || x + y <= 0) return -1;
x = x % mod;
y = y % mod;
return 1;
}
struct Data{
ll a[2][2];
}d0,d1;
Data operator * (Data x, Data y){
Data ans;
for(int i = 0; i < 2; i++){
for(int j = 0; j < 2; j++){
ans.a[i][j] = 0;
for(int k = 0; k < 2; k++){
ans.a[i][j] += x.a[i][k] * y.a[k][j];
if(ans.a[i][j] >= mod) ans.a[i][j] %= mod;
}
}
}
return ans;
}
Data gd(ll k){
if(k == 0) return d1;
Data d = gd(k >> 1);
d = d * d;
if(k & 1) d = d * d0;
return d;
}
ll fibo2(ll x){
if(x <= 10) return fibo[x] % mod;
Data d = gd(x - 1);
return d.a[1][0];
}
int main(){
fibo[0] = 1, fibo[1] = 0;
for(int i = 2; i < 100; i++) fibo[i] = fibo[i-2] + fibo[i-1];
d0.a[0][0] = 0, d0.a[0][1] = 1;
d0.a[1][0] = 1, d0.a[1][1] = 1;
d1.a[0][0] = 1, d1.a[0][1] = 0;
d1.a[1][0] = 0, d1.a[1][1] = 1;
int T;
scanf("%d",&T);
for(int kase = 1; kase <= T; kase++){
ll n, x, m, y, k;
scanf("%lld%lld%lld%lld%lld",&n,&x,&m,&y,&k);
if(n >= 80 || m >= 80){
printf("Impossible\n");
continue;
}
ll n1, n2;
int res = getans(fibo[n-1] + fibo[n], fibo[n] + fibo[n+1], x, fibo[m-1] + fibo[m], fibo[m] + fibo[m+1], y, n1, n2);
if(res == -1) printf("Impossible\n");
else{
ll ans = (fibo2(k-1) + fibo2(k)) % mod * n1 % mod + (fibo2(k) + fibo2(k+1)) % mod * n2 % mod;
printf("%lld\n",ans % mod);
}
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。