UVA - 12045 Fun with Strings

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

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

时间: 2024-10-13 00:17:52

UVA - 12045 Fun with Strings的相关文章

UVa 10679 - I Love Strings!!

题目:给你一个目标串,和一些模式串,问每个模式串是否在目标串中出现. 分析:字符串,AC自动机.一开始用KMP算法,TLE了才发现会超时,改用AC自动机: 直接利用AC自动机存储,查询即可,然后按顺序输出: 如果模式串中有重复的,直接利用并查集合并即可,只须判断父节点. 说明:╮(╯▽╰)╭计算复杂度时,数据组数被忽略了:注意初始化. #include <iostream> #include <cstdlib> #include <cstring> #include &

UVA 10679 I love Strings!!!(AC自动机)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1620 题意: 给出一个文本串和若干个模式串,问模式串是否在文本串中出现过. 分析: 简单粗暴的AC自动机模板题,要注意模式串可能有重复的情况. /* * * Author : fcbruce * * Time : Sat 04 Oct 2014 03:30:15 PM CST * */ #i

UVa OJ 455 Periodic Strings

 Periodic Strings  A character string is said to have period k if it can be formed by concatenating one or more repetitions of another string of length k. For example, the string "abcabcabcabc" has period 3, since it is formed by 4 repetitions o

UVA - 11127 Triple-Free Binary Strings dfs

题目大意:有一个字符串,这个字符串由0,1和*组成,*可以变成0也可以变成1,要求变化后的字符串的字符只能是0或者1. 现在给出这个字符串,要求变化后的字符串中不能出现三个连续相同的子串,问最多可以变化成多少个符合规则的串 解题思路:因为只有0和1,且只有30位,所以可以用一个正数来表示状态.dfs暴力枚举,边枚举边判断,看当前的是否符合 #include<cstdio> #include<cstring> using namespace std; #define maxn 35

(UVA)455 --Periodic Strings(周期串)

题目链接:http://vjudge.net/problem/UVA-455 可以从1开始枚举周期,对后面的字符逐个测试. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int main() 7 { 8 int t; 9 char s[100]; 10 scanf("%d",&t); 11 while(t--)

UVa 10298 - Power Strings

题目:求一个串的最大的循环次数. 分析:dp,KMP,字符串.这里利用KMP算法. KMP的next函数是跳跃到最近的串的递归结构位置(串元素取值0 ~ len-1): 由KMP过程可知: 如果存在循环节,则S[0 ~ next[len]-1] 与 S[len-next[len] ~ len-1]相匹配: 则S[next[len] ~ len-1]就是循环节(且最小),否则next[len]为0: 因此,最大循环次数为len/(len-next[len]),最小循环节为S[next[len] ~

UVA - 10298 Power Strings (KMP求字符串循环节)

Description Problem D: Power Strings Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiati

UVa 10745 - Dominant Strings

题目:给你一些字符串,问哪些字符串不是其他字符串的子集,字符串的集合为字母组成的重集. 分析:字符串,dancing-links.Knuth有一篇关于dancing-links的论文,讲述关于搜索的优化. 在搜索时,将所有的状态建立一个链表,表之间的状态建立相互关系. 每次搜索时,进行剪枝,将不成立的节点从链表中删掉,回溯时在拼上去. 用数组建立链表,高效方便,存储L,R左右两端下标即可. 本题直接进行删除即可. 如果,一个字符串的补集是另一个字符串的子集,这个字符串的集合一定是另一的超集. 解

UVA 10298 - Power Strings(KMP)

UVA 10298 - Power Strings 题目链接 题意:本意其实就是,给定一个字符串,求出最小循环节需要几次循环出原字符串 思路:利用KMP中next数组的性质,n - next[n]就是最小循环节,然后n / 循环节就是答案 代码: #include <cstdio> #include <cstring> const int N = 1000005; char str[N]; int next[N]; void getnext() { int n = strlen(s