zoukankan      html  css  js  c++  java
  • 暑假D16 T3 密道(数位DP? 打表找规律)

    题意

    对于一个(n+1)*(n+1)的矩阵,第一列和第一排为1,其他位置为1当且仅当上方和左方有一个1,其他为0;

    对于100%的数据,n<=1e9

    题解

    稍微画了一下,感觉从图像看不大出来,就去打了一个表:

    1,3,7,9,17,21,25,27,43,51,59,63,71,75,81;

    这种东西一般就求差再看看,就会发现:2,4,2,8,4,4,2,16,8,8,4,8,4,4,2

    这样还看不大出来,再分析数据对于30%的数据n=2k-1,发现这个范围的答案就是3k,于是直觉就分出了组

    2

    4,2

    8,4,4,2

    16,8,8,4,8,4,4,2

    那么就比较明显了吧,下面一排前一半是上一排*2,后一半就是上一排。

    那么就想到一种做法,先把n分成2k+n',就得到3k,剩下n'部分再递归处理,他是一个组的一部分,再这个组的前一半的部分就是上一个组的一半,在这个组后一半的部分直接递归。

    注意记忆化就ok,可以用map记忆化,其实差不多,map还有查找速度,虽然数组只能只能开1e6。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    const int maxn=1000005;
    ll n;
    ll ans,f[35][maxn];
    
    int get(int x){
        int ret=-1;
        while(x){
            x>>=1;
            ret++;
        }
        return ret;
    }
    
    ll qpow(ll a,ll b){
        ll ret=1;
        while(b){
            if(b&1) ret*=a;
            a*=a;
            b>>=1;
        }
        return ret;
    }
    
    ll dfs(int s,int k){//第s组,前k项 
        if(s==1) return  2;
        if(k<maxn&&f[s][k]) return f[s][k];
        ll mid=(1<<(s-2)),ret;
        if(k<=mid) ret=dfs(s-1,k)<<1;
        else ret=dfs(s-1,k-mid)+(dfs(s-1,mid)<<1);
        if(k<maxn) f[s][k]=ret;
        return ret;
    }
    
    int main(){
        freopen("c.in","r",stdin);
        freopen("c.out","w",stdout);
        scanf("%lld",&n);
        n++;
        int k=get(n);
        ans+=qpow(3,k);
        n-=(1<<k);
        if(!n) {printf("%lld",ans);return 0;}
        ans+=dfs(k+1,n);
        printf("%lld",ans);
    }
    View Code

    不过他们的规律好像和我不大一样,他们直接从答案入手,给出代码,具体原因之后再看。(code from ltw)

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<map> 
    using namespace std;
    long long n;
    map < int,long long > mp;
    long long solve (long long x){
        if (x==1) return 1;
        if (x==2) return 3;
        if (mp[x]) return mp[x];
        return mp[x]=2*solve (ceil ((double)(x/2.0)))+solve (floor ((double(x/2.0))));
    }
    int main(){
        freopen ("c.in","r",stdin); freopen ("c.out","w",stdout);
        scanf ("%lld",&n);
        printf ("%lld",solve (n+1));
    }
    View Code

    还有看图像找规律的,三个1组成一个小三角形,再三个又是一个更大的。

    先取一个lowbit(就是分解成2k+n'),然后再怎么搞搞就OK了。(咱也不知道,咱也不敢问)

    不过正解好像是数位DP?讲这个图形旋转45°就是杨辉三角?然后在利用Lucas定理?

    话说今天数论都是打表搞的,这真是一个好方法。(掩饰自己不会数论)

    顺便%%sxk  dalao,AK

  • 相关阅读:
    Python3 B格注释
    python 安装模块时提示报错:Microsoft Visual C++ 9.0 is required (Unable to find vcvarsall.bat)
    sed的使用(数据的截取与插入)
    常见软件的安装
    淘宝镜像
    搭建 Node.js 开发环境
    解决 /lib64/libc.so.6: version `GLIBC_2.14' not found 的问题
    linux下 执行命令时提示cannot execute binary file
    web页面 显示 Resource interpreted as Stylesheet but transferred with MIME type text/plain的错误警告
    python+QT designer 做图形化界面EXE程序
  • 原文地址:https://www.cnblogs.com/sto324/p/11266357.html
Copyright © 2011-2022 走看看