zoukankan      html  css  js  c++  java
  • 【题解】Kathy函数 [BZOJ1223] [P2235] [HNOI2002]

    【题解】Kathy函数 [BZOJ1223] [P2235] [HNOI2002]


    这几疯狂刷了数位(dp)的题,到这道题时被卡了一天,一看大佬的讲解发现居然是求回文数╮(╯_╰)╭
    感觉被大佬狠狠地蹂蹑了一番。。。

    废话到此结束,进入正题:

    满足(f(n)=n)(n)在二进制的形式下一定是一个回文数

    例如:

    (f(1)=1) ((1))
    (f(3)=3) ((11))
    (f(5)=5) ((101))
    (f(7)=7) ((111))

    至于为什么会有这个性质,这里就作证明(都懒得给自己的懒惰找借口了)

    假设已经成功的证明了这个结论,那么问题就变成了在([1,n])中找到符合二进制形式为回文数的总个数,这里我提供一种用(dfs)实现数位(dp)的思路

    可以先写一下这道题(因为不需要高精):
    只需要输出区间内回文数的总个数

    LightOJ1205


    (dfs)找回文数个数:

    一:转进制

    首先我们需要把(n)转化为二进制存储在一个数组(num[lenn])

    二:DFS

    (dfs(st,pos,ok,limit))

    记搜以及状态表示

    用一个数组记录已经搜过的地方,(dp[pos][ok][st]) 示已经选到了第(pos)位,前已经选好的是否满足回文(ok),去前导(0)后共有(st)位,并且前面已选的并未全部达到上限((pos)开始后面可以随意选(0)(1)),此时的回文数总数。

    (limit)表示前面已选的是否全达到上限,如果是,那么这一位的可以选的数的上限为(num[pos]),否则可以随意选,(ed=limit?num[pos]:1)

    如果当前状态并未受限,且当前状态的(dp)值已经被记录,直接返回这个值

    如何枚举递归

    每当选了一个数(i)时, (tmp[pos]=i)

    (1) 如果前面都没选(即全是前(0)(st=pos)),
    (ans+=dfs)((st-1),(pos-1),(ok),(limit)&&(i==ed))

    (2) 如果前面选了(即(st>pos)

    1. 如果当前状态是回文数,且当前选的这位在(st)的后半段(即(ok)&&(pos<=st/2)),则(okk=tmp[st-pos+1]==i)
    2. 否则 (okk=ok)
      (ans+=dfs)((st),(pos-1),(okk),(limit)&&(i==ed))

    (dfs)边界

    (pos==0)(即已经选完了所有位)
    如果满足回文数(即(ok=1))且选了数(即并非全是(0)(st>0)(return 1)

    三.高精

    推荐写结构体,用起来方便,不会的可以参考一下大佬的高精模板

    最后附上代码:

    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int base = 1e8;
    const int N = 20;
    int aux[N << 3];
    struct bigint {
        int s[N], l;
        void CL() { l = 0; memset(s, 0, sizeof(s)); }
        void pr()
        {
            printf("%d", s[l]);
            for (int i = l - 1; i; i--)
                printf("%08d", s[i]);
        }
        void re_l()
        {
            int i, x = 0, k = 1, L = 0, fl, o;
            char c = getchar();
            for (; c < '0' || c > '9'; c = getchar());
            for (; c >= '0' && c <= '9'; c = getchar())
            {
                if (!(L - 1) && !aux[L])
                    L--;
                aux[++L] = c - '0';
            }
            CL();
            l = L / 8 + ((o = L % 8) > 0);
            for (i = 1; i <= o; i++)
                x = x * 10 + aux[i];
            if (o)
                s[l] = x;
            fl = !o ? l + 1 : l;
            for (i = o + 1, x = 0; i <= L; i++, k++)
            {
                x = x * 10 + aux[i];
                if (!(k ^ 8))
                {
                    s[--fl] = x;
                    x = k = 0;
                }
            }
            if (!l)
                l = 1;
        }
        ll toint()
        {
            ll x = 0;
            for (int i = l; i; i--)
                x = x * base + s[i];
            return x;
        }
        bigint operator = (int b)
        {
            CL();
            do
            {
                s[++l] = b % base;
                b /= base;
            } while (b > 0);
            return *this;
        }
        bigint operator = (ll b)
        {
            CL();
            do
            {
                s[++l] = b % base;
                b /= base;
            } while (b > 0);
            return *this;
        }
        bigint operator + (const int &b)
        {
            bigint c = *this;
            ll x = b;
            for (int i = 1; i <= l && x; i++)
            {
                x = x + c.s[i];
                c.s[i] = x % base;
                x /= base;
            }
            if(x)c.s[++c.l] = x;
            return c;
        }
        bigint operator + (const ll &b)
        {
            bigint c = *this;
            ll x = b;
            for (int i = 1; i <= l && x; i++)
            {
                x = x + c.s[i];
                c.s[i] = x % base;
                x /= base;
            }
            if (x)
                c.s[++c.l] = x;
            return c;
        }
        bigint operator + (bigint &b)
        {
            if (b.l < 3)
                return *this + b.toint();
            bigint c;
            ll x = 0;
            int k = l < b.l ? b.l : l;
            c.CL();
            c.l = k;
            for (int i = 1; i <= k; i++)
            {
                x = x + s[i] + b.s[i];
                c.s[i] = x % base;
                x /= base;
            }
            if (x)
                c.s[++c.l] = x;
            return c;
        }
        bigint operator / (const int &b)
        {
            bigint c;
            ll x = 0;
            c.CL();
            for (int i = l; i; i--)
            {
                c.s[i] = (x * base + s[i]) / b;
                x = (x * base + s[i]) % b;
            }
            for (c.l = l; !c.s[c.l] && c.l > 1; c.l--);
            return c;
        }
        bigint operator % (const int &b)
        {
            bigint c;
            ll x = 0;
            c.CL();
            for (int i = l; i; i--)
                x = (x * base + s[i]) % b;
            return c = x;
        }
        bool operator > (const bigint &b) const
        {
            if (l ^ b.l)
                return l > b.l;
            for (int i = l; i; i--)
                if (s[i] ^ b.s[i])
                    return s[i] > b.s[i];
            return false;
        }
        bigint operator += (bigint &b)
        {
            return *this = *this + b;
        }
        bool operator > (int b) const{
            bigint c;return *this > (c = b);
        }
    };
    //以上皆为高精度部分
    
    bigint a;
    int num[350],tmp[350];bigint dp[350][2][350];
    bool pan[350][2][350];
    inline bigint dfs(int st,int len,int ok,bool limit){
        bigint ans,pp;ans=0;pp=0;
    	if(len<1){//边界 
        	if(ok&&st>0)ans=1;
        	return ans;
        }
        if(!limit&&pan[len][ok][st])return dp[len][ok][st];//返回所记录的值 
        int ed=limit?num[len]:1;//处理枚举上限 
        for(int i=0;i<=ed;i++){
            tmp[len]=i;//记录每次选的数,方便判断是否满足回文 
            if(st==len&&!i)pp=dfs(st-1,len-1,ok,limit&&i==ed),ans+=pp;//如果一直都没选数 
            else pp=dfs(st,len-1,(ok&&len<=st/2)?tmp[st-len+1]==i:ok,limit&&i==ed),ans+=pp;//如果选了数 
    	}
        if(!limit)dp[len][ok][st]=ans,pan[len][ok][st]=1;//记录 
        return ans;
    }
    int main(){
        a.re_l();ll Lenn=0;
        while(a>0){num[++Lenn]=(a%2).toint();a=(a/2);}//转成2进制存起来 
        bigint ans=dfs(Lenn,Lenn,1,1);
        ans.pr();
        return 0;
    }
    

    -----若要转载请私信作者获得许可并在文首标出转载来源-----

  • 相关阅读:
    关于lockkeyword
    关于多层for循环迭代的效率优化问题
    Android 面试精华题目总结
    Linux基础回想(1)——Linux系统概述
    linux源代码编译安装OpenCV
    校赛热身 Problem C. Sometimes Naive (状压dp)
    校赛热身 Problem C. Sometimes Naive (状压dp)
    校赛热身 Problem B. Matrix Fast Power
    校赛热身 Problem B. Matrix Fast Power
    集合的划分(递推)
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/10717138.html
Copyright © 2011-2022 走看看