• D. Infinite Set 题解(思维+dp)


    题目链接

    题目思路

    首先要观察它需要的数是小于\(2^p\),那么需要往二进制的思路去想就简单很多

    \(x=2y+1\) 本质上就是在二进制的表现下末尾加一个1

    \(x=4y\) 本质上就是在二进制的表现下末尾加两个\(00\)

    那么如果一个二进制长度为\(len\)的数\(x\)

    它要延申成长度为\(len+1\)位有\(1\)

    它要延申成长度为\(len+2\)位有\(2\)

    它要延申成长度为\(len+3\)位有\(3\)

    这就是斐波那契数列

    定义\(\sum_{i=0}^{i=n} fac[i]=sum[n]\)

    那么如果他要延申成长度小于\(p\)位有\(sum[p-len]\)

    那么对于一个数的情况解决了,那么对于多个数的情况就是需要去重

    加入\(x\)可以生成\(y\),那么需要去掉\(y\)

    那么假如\(y\)是奇数,\(y/=2\) 。假如\(y\)\(4\)的倍数,\(y/=4\) 看中途是否出现过即可

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
    const double eps=1e-6;
    int n,p;
    int a[maxn];
    ll ans;
    ll fac[maxn],sum[maxn];
    map<int, bool> mp;
    int cal(int x){
        int len=0;
        while(x){
            x/=2;
            len++;
        }
        return len;
    }
    signed main(){
        fac[0]=fac[1]=1;
        sum[0]=1;
        sum[1]=2;
        for(int i=2;i<=2e5;i++){
            fac[i]=(fac[i-1]+fac[i-2])%mod;
            sum[i]=(sum[i-1]+fac[i])%mod;
        }
        scanf("%d%d",&n,&p);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            mp[a[i]]=true;
        }
        for(int i=1;i<=n;i++){
            int tmp=a[i];
            bool flag=false;
            while(tmp){
                if(tmp%2){
                    tmp/=2;
                }else if(tmp%4==0){
                    tmp/=4;
                }else{
                    break;
                }
                if(mp.count(tmp)){
                    flag=true;
                    break;
                }
            }
            if(flag) continue;
            int len=cal(a[i]);
            if(p-len>=0){
                ans=(ans+sum[p-len])%mod;
            }
        }
        printf("%lld\n",ans);
        return 0;
    }
    

    题目链接

    题目思路

    首先要观察它需要的数是小于\(2^p\),那么需要往二进制的思路去想就简单很多

    \(x=2y+1\) 本质上就是在二进制的表现下末尾加一个1

    \(x=4y\) 本质上就是在二进制的表现下末尾加两个\(00\)

    那么如果一个二进制长度为\(len\)的数\(x\)

    它要延申成长度为\(len+1\)位有\(1\)

    它要延申成长度为\(len+2\)位有\(2\)

    它要延申成长度为\(len+3\)位有\(3\)

    这就是斐波那契数列

    定义\(\sum_{i=0}^{i=n} fac[i]=sum[n]\)

    那么如果他要延申成长度小于\(p\)位有\(sum[p-len]\)

    那么对于一个数的情况解决了,那么对于多个数的情况就是需要去重

    加入\(x\)可以生成\(y\),那么需要去掉\(y\)

    那么假如\(y\)是奇数,\(y/=2\) 。假如\(y\)\(4\)的倍数,\(y/=4\) 看中途是否出现过即可

    代码

    #include<bits/stdc++.h>
    #define fi first
    #define se second
    #define debug cout<<"I AM HERE"<<endl;
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
    const double eps=1e-6;
    int n,p;
    int a[maxn];
    ll ans;
    ll fac[maxn],sum[maxn];
    map<int, bool> mp;
    int cal(int x){
        int len=0;
        while(x){
            x/=2;
            len++;
        }
        return len;
    }
    signed main(){
        fac[0]=fac[1]=1;
        sum[0]=1;
        sum[1]=2;
        for(int i=2;i<=2e5;i++){
            fac[i]=(fac[i-1]+fac[i-2])%mod;
            sum[i]=(sum[i-1]+fac[i])%mod;
        }
        scanf("%d%d",&n,&p);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            mp[a[i]]=true;
        }
        for(int i=1;i<=n;i++){
            int tmp=a[i];
            bool flag=false;
            while(tmp){
                if(tmp%2){
                    tmp/=2;
                }else if(tmp%4==0){
                    tmp/=4;
                }else{
                    break;
                }
                if(mp.count(tmp)){
                    flag=true;
                    break;
                }
            }
            if(flag) continue;
            int len=cal(a[i]);
            if(p-len>=0){
                ans=(ans+sum[p-len])%mod;
            }
        }
        printf("%lld\n",ans);
        return 0;
    }
    
  • 相关阅读:
    WPF学习笔记(三)
    WPF自定义控件——使用Win32控件
    WPF学习笔记(二)
    WPF自定义控件 —— 装饰器
    WPF中改进自定义Command一些想法
    WPF自定义控件 —— 布局
    制作WPF联机飞行棋的失败体验
    WPF自定义控件 —— 自绘篇
    c语言清屏、等待、随机函数
    c语言一个显示星号的函数(隐藏密码)
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/15918294.html
Copyright © 2020-2023  润新知