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

HDU 6768 - The Oculus


题意

定义Fi为斐波那契数列第i项,F1=1, F2=2, Fi=Fi1+Fi2 (i3)

已知任意正整数x都拥有一个唯一的长度为n01数列{b},使得

b1F1+b2F2+...+bnFn=x

bn=1

bi{0,1}

bibi+1=0

以这样的表示法给出ABC三个数

已知数字C是由AB的结果在这样的表示法下将某个原本是1的位置改成0得来的

问抹去的是哪个位置


数据范围

1T10000

1|A|,|B|1000000

2|C||A|+|B|+1

|A|,|B|5000000



根据数据范围,至少要预处理出前2000001项的斐波那契数列

并通过map/unordered_map/gp_hash_table将值映射回位置

然后根据题目所述,计算出ABC的值

其次只要通过ABC来计算出被抹去的数对应的数字是什么,将映射的位置输出即可

想法理解了之后就只剩处理方法的问题了

首先发现Fibonacci数列前100项便会超出long long的范围,所以需要对其进行取模

我们需要保证这个模数能让Fibonacci数列前2000001项在取模后没有冲突(唯一性)

所以需要一个比平时见到的模数更大的模数去尝试(类似9982443531000000007这些均有冲突项数)

最后我取了1111111111139这个模数(若使用unsigned long long可以使用哈希的想法让数自然溢出,应该也是对的)

于是就能预处理+映射求出答案了,详见代码

需要注意的是,模数过大可能会导致计算AB时超出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来代替,时间复杂度可以降低23倍,但空间复杂度会提高1.52

在实际使用过程中,除了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;
}
posted @   StelaYuri  阅读(505)  评论(4编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示