码迷,mamicode.com
首页 > 其他好文 > 详细

UVA - 12045 Fun with Strings

时间:2015-08-21 00:21:43      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:fibonaaci   矩阵快速幂   二元一次方程   

题意:有一个非空字符串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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

UVA - 12045 Fun with Strings

标签:fibonaaci   矩阵快速幂   二元一次方程   

原文地址:http://blog.csdn.net/uestc_peterpan/article/details/47817015

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!