2020杭電多校 2F / HDU 6768 - The Oculus (哈希)


HDU 6768 - The Oculus


題意

定義\(F_i\)為斐波那契數列第\(i\)項,\(F_1=1,\ F_2=2,\ F_i=F_{i-1}+F_{i-2}\ (i≥3)\)

已知任意正整數\(x\)都擁有一個唯一的長度為\(n\)\(01\)數列\(\{b\}\),使得

\(b_1*F_1+b_2*F_2+...+b_n*F_n=x\)

\(b_n=1\)

\(b_i∈\{0,1\}\)

\(b_i*b_{i+1}=0\)

以這樣的表示法給出\(A、B、C\)三個數

已知數字\(C\)是由\(A*B\)的結果在這樣的表示法下將某個原本是\(1\)的位置改成\(0\)得來的

問抹去的是哪個位置


數據范圍

\(1≤T≤10000\)

\(1≤|A|,|B|≤1000000\)

\(2≤|C|≤|A|+|B|+1\)

\(\sum|A|,\sum|B|≤5000000\)



根據數據范圍,至少要預處理出前\(2000001\)項的斐波那契數列

並通過\(map/unordered\_map/gp\_hash\_table\)將值映射回位置

然后根據題目所述,計算出\(A\)\(B\)\(C\)的值

其次只要通過\(A*B-C\)來計算出被抹去的數對應的數字是什么,將映射的位置輸出即可

想法理解了之后就只剩處理方法的問題了

首先發現\(Fibonacci\)數列前\(100\)項便會超出\(long\ long\)的范圍,所以需要對其進行取模

我們需要保證這個模數能讓\(Fibonacci\)數列前\(2000001\)項在取模后沒有沖突(唯一性)

所以需要一個比平時見到的模數更大的模數去嘗試(類似\(998244353、1000000007\)這些均有沖突項數)

最后我取了\(1111111111139\)這個模數(若使用\(unsigned\ long\ long\)可以使用哈希的想法讓數自然溢出,應該也是對的)

於是就能預處理+映射求出答案了,詳見代碼

需要注意的是,模數過大可能會導致計算\(A*B\)時超出\(long\ long\)的范圍,所以需要使用快速乘



完整程序(各種優化情況)

由於組數關系及數據范圍,所以我們需要考慮應當選取怎樣的容器去映射

經(不完全)測試,得到結果如下

容器/讀入方式 賽時測評(ms) 題庫測評(ms)
map + STDIO / TLE
unordered_map + STDIO 2453 /
gp_hash_table + STDIO 2015 /
unordered_map + FastIO / 2698
gp_hash_table + FastIO 375 1107

數據過大,快讀這題在題庫測評時應該是少不了的

其次稍微提一下,如果提交的是\(G++\),且需要使用\(unordered\_map\)類時

如果空間充足,建議使用\(gp\_hash\_table\)來代替,時間復雜度可以降低\(2\)$3$倍,但空間復雜度會提高$1.5$\(2\)

在實際使用過程中,除了\(gp\_hash\_table\)無法使用\(count\)函數外,其余與\(unordered\_map\)相同

使用方法如下(兩個頭文件&一個namespace,添加后就能使用了)

下面展示的是\(gp\_hash\_table + FastIO\)組合的程序

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;

const int bsz=1<<18;
char bf[bsz],*head,*tail;
inline char gc(){
    if(head==tail){
        int l=fread(bf,1,bsz,stdin);
        tail=(head=bf)+l;
    }
    return *head++;
}
inline int read(){
    int x=0,f=1;
    char c=gc();
    for(;!isdigit(c);c=gc())
        if(c=='-')
            f=-1;
    for(;isdigit(c);c=gc())
        x=x*10+c-'0';
    return x*f;
}
inline void write(ll x){
    if(x>=10)
        write(x/10);
    putchar(x%10+'0');
}
inline void putd(ll x)
{
    write(x);
    putchar('\n');
}

const ll mod=1111111111139LL;

gp_hash_table<ll,int> mp;
ll fibo[2000050];

ll qmul(ll a,ll b){ //快速乘
    ll r=0;
    while(b){
        if(b&1)
            r=(r+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return r;
}

void solve()
{
    int cnt1,cnt2,cnt3,d;
    ll A=0,B=0,C=0;
    
    cnt1=read();
    for(int i=1;i<=cnt1;i++)
    {
        d=read();
        if(d==1)
            A=(A+fibo[i])%mod;
    }
    cnt2=read();
    for(int i=1;i<=cnt2;i++)
    {
        d=read();
        if(d==1)
            B=(B+fibo[i])%mod;
    }
    cnt3=read();
    for(int i=1;i<=cnt3;i++)
    {
        d=read();
        if(d==1)
            C=(C+fibo[i])%mod;
    }
    
    putd(mp[(qmul(A,B)-C+mod)%mod]);
}
int main()
{
    fibo[0]=fibo[1]=1;
    mp[1]=1;
    for(int i=2;i<=2000010;i++)
    {
        fibo[i]=(fibo[i-1]+fibo[i-2])%mod;
        mp[fibo[i]]=i;
    }
    
    int T=read();
    while(T--)
        solve();
    
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM