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;
    }
    

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

  • 相关阅读:
    Android多屏幕适配
    android应用签名详解
    内部类与静态内部类详解
    SpringBoot整合Spring Retry实现重试机制
    行为型模式之模板方法模式
    行为型模式之操作复杂对象结构(访问者模式)
    行为型模式之算法的封装与切换(策略模式)
    行为型模式之处理对象的多种状态及其相互转换(状态模式)
    行为型模式之对象间的联动(观察者模式)
    行为型模式之撤销功能的实现(备忘录模式)
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/10717138.html
Copyright © 2011-2022 走看看