数论 + 哈希 - The Oculus - HDU 6768

数论 + 哈希 - The Oculus - HDU 6768

2020 Multi-University Training Contest 2

题意:

F 1 , F 2 , . . . F 1 = 1 , F 2 = 2 , F i = F i 1 + F i 2 ( i 3 ) 定义斐波那契数列:F_1,F_2,...,F_1=1,F_2=2,F_i=F_{i-1}+F_{i-2}(i≥3)

x 众所周知,任意的正整数x可由斐波那契数列的几项和来表示。

x n ( b 1 , b 2 , . . . , b n ) 抽象地,即对任意的正整数x,存在n元组(b_1,b_2,...,b_n),满足:

  • b 1 × F 1 + b 2 × F 2 + . . . + b n × F n = x b_1×F_1+b_2×F_2+...+b_n×F_n=x
  • b n = 1 i [ 1 , n 1 ] b i b_n=1,且对任意i∈[1,n-1],b_i∈ { 0 , 1 0,1 } 恒成立。
  • i [ 1 , n 1 ] b i × b i + 1 = 0   对任意的i∈[1,n-1],b_i×b_{i+1}=0\ 恒成立。

4 = ( 1 , 0 , 1 ) , 5 = ( 0 , 0 , 0 , 1 ) , 20 = ( 0 , 1 , 0 , 1 , 0 , 1 )   20 = F 2 + F 4 + F 6 = 2 + 5 + 13. 例如: 4=(1,0,1), 5=(0,0,0,1), 20=(0,1,0,1,0,1) ,因为\ 20=F_2+F_4+F_6=2+5+13.

T T组测试样例。

每组测试样例输入三行数据,

n i n i 0 1 每行包括一个长度n_i,和一个长度为n_i的由0和1构成的序列,

A B C 分别表示A、B和C的斐波那契序列的表示。

C 1 0 使 A × B = C 已知C的斐波那契表示的某一位的1被修改成了0,请找出这个位置,使得修改后,满足A×B=C。

Sample Input

1
3 1 0 1
4 0 0 0 1
6 0 1 0 0 0 1

Sample Output

4

数据范围:

1 T 10000 ,   1 A , B 1000000   2 C A + B + 1   A , B 5000000 1≤T≤10000,\\ \ \\ 1≤|A|,|B|≤1000000,\\ \ \\2≤|C|≤|A|+|B|+1,\\ \ \\∑|A|,∑|B|≤5000000


分析:

A B X = A × B C X 本题很自然地能够想到,先求出A和B,记X=A×B-C,判断X是斐波那契数列的第几项。

A B X 计算A和B,以及查询X的位置,都需要预处理出斐波那契数列的部分项。

C 2000001 2 × 1 0 6 考虑到C的长度可能达到2000001项,故我们要先做大约2×10^6的预处理。

1 0 18 由于项数较多,已经早早的溢出了10^{18},因此我们计算时,需要对斐波那契数列取模。

( A × B ) % P = ( C + X ) % P 根据题意,有:(A×B)\%P=(C+X)\%P

( A × B ) % P C % P = X % P 即:(A×B)\%P-C\%P=X\%P

X % P X % 我们计算出X\%P后,在预处理的斐波那契数列中查找X\%所在的位置即可。

( . . . ) (题解直接建议用无符号的长整型,让其自然溢出...)

( ) 经过测试,取双模数是可以避免冲突的。(单模数还是冲突一大堆)

p a i r 因此我们用pair来存储对两个不同模数取模后的斐波那契数列。

A B C P 1 P 2 ( X 1 , X 2 ) 对A、B、C对两个模数P_1和P_2取模,接着在预处理的斐波那契数列中查找(X_1,X_2)所在的位置即可。

注意:

最后的查找位置不能用二分,因为取模后,新的序列不是单调序列!

直接遍历查找即可。


双模数:
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>

#define ll long long
#define P pair<int,int>
#define x first
#define y second

using namespace std;

const int N=2e6, mod1=805306457, mod2=201326611;

int A[N+10],B[N+10],C[N+10];
P f[N+10];

void Init()
{
    f[1].x=f[1].y=1,f[2].x=f[2].y=2;
    for(int i=3;i<=N+5;i++)
    {
        f[i].x=(f[i-1].x+f[i-2].x)%mod1;
        f[i].y=(f[i-1].y+f[i-2].y)%mod2;
    }
}

int add_mod(int a,int b,int mod)
{
    ll t=0;
    t=a+b;
    if(t>=mod) t%=mod;
    return t;
}

int main()
{
    Init();

    int T,n1,n2,n3;
    cin>>T;
    while(T--)
    {
        P a,b,c;
        int a1=0,a2=0,b1=0,b2=0,c1=0,c2=0;

        scanf("%d",&n1);
        for(int i=1;i<=n1;i++)
        {
            scanf("%d",&A[i]);
            if(A[i]) 
            {
                a1=add_mod(a1,f[i].x,mod1);
                a2=add_mod(a2,f[i].y,mod2);
            }
        }
        a={a1,a2};

        scanf("%d",&n2);
        for(int i=1;i<=n2;i++)
        {
            scanf("%d",&B[i]);
            if(B[i]) 
            {
                b1=add_mod(b1,f[i].x,mod1);
                b2=add_mod(b2,f[i].y,mod2);
            }
        }
        b={b1,b2};
        
        scanf("%d",&n3);
        for(int i=1;i<=n3;i++)
        {
            scanf("%d",&C[i]);
            if(C[i]) 
            {
                c1=add_mod(c1,f[i].x,mod1);
                c2=add_mod(c2,f[i].y,mod2);
            }
        }
        c={c1,c2};
        
        int d1=(ll)a.x*b.x%mod1;
        int d2=(ll)a.y*b.y%mod2;
        for(int i=1;;i++)
            if(f[i].x==(d1-c.x+mod1)%mod1 && f[i].y==(d2-c.y+mod2)%mod2)
            {
                printf("%d\n",i);
                break;
            }
    }

    return 0;
}

自然溢出:
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>

#define ll unsigned long long

using namespace std;

const int N=2e6;

int A[N+10],B[N+10],C[N+10];
ll f[N+10];

void Init()
{
    f[1]=1,f[2]=2;
    for(int i=3;i<=N+5;i++) f[i]=f[i-1]+f[i-2];
}

int main()
{
    Init();

    int T,n1,n2,n3;
    cin>>T;
    while(T--)
    {
        ll a=0,b=0,c=0;

        scanf("%d",&n1);
        for(int i=1;i<=n1;i++)
        {
            scanf("%d",&A[i]);
            if(A[i]) a+=f[i];
        }

        scanf("%d",&n2);
        for(int i=1;i<=n2;i++)
        {
            scanf("%d",&B[i]);
            if(B[i]) b+=f[i];
        }

        scanf("%d",&n3);
        for(int i=1;i<=n3;i++)
        {
            scanf("%d",&C[i]);
            if(C[i]) c+=f[i];
        }

        a*=b;
        for(int i=1;;i++)
            if(c+f[i]==a)
            {
                printf("%d\n",i);
                break;
            }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/njuptACMcxk/article/details/107546148