1 条题解

  • 0
    @ 2025-8-24 22:00:25

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar WinXP
    **

    搬运于2025-08-24 22:00:25,当前版本为作者最后更新于2018-05-23 22:19:55,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    #啊

    我一定要写这篇题解祭奠我逝去的一下午

    拿到这题,乍一看是一个 dpdp 题。也的确是一个 dpdp,而且非常水。

    根据题中关于 44 连环的解释,你可以发现 44 连环的拆卸就是这样的一个规律:

    11 : 拆 22 连坏使其变为 11001100

    22 : 拿掉最左面的 11 ;

    33 : 加 22 连环使其变为 01110111

    44 : 拆 33 连环。

    仔细观察,两条规则中都是"任意装上或卸下。"那么可想而知装 xx 连环与卸 xx 连环都是同样的步数。

    所以设 dp(x)dp(x) 表示 xx 连环拆卸的次数,这题已经结束了。(才怪)

    dp(4)=dp(2)+1+dp(2)+dp(3)dp(4)=dp(2) + 1 + dp(2) + dp(3)

    dp(n)=dp(n2)dp(n)=dp(n-2) (拆 (n2)(n-2) 连环变成 110000...110000...++ 11 ( 010000...010000... ) ++ dp(n2)dp(n-2) (装 (n2)(n-2) 连环变成 011111...011111... ) ++ dp(n1)dp(n-1) (拆 (n1)(n-1) 连环)。

    dp(n)=2dp(n2)+dp(n1)+1dp(n)=2dp(n-2)+dp(n-1)+1

    于是我兴致冲冲地打了一发递推交上去30分。

    然后我发现了一个问题:没有取膜?

    没有取膜。我说怎么那么水。

    于是我陷入了沉思。

    沉思之中顺手打了个表:

    11 22 55 1010 2121 4242 8585 170...170...

    发现一个问题。每一项约等于前一项的 22 倍。仔细分析,发现

    dp(n)=2dp(n1)+(n&1)?1:0dp(n)=2dp(n-1)+ (n\&1)?1:0

    既然是 22 倍,为什么不打一下 22 进制表示呢?

    11 1010 101101 10101010 1010110101 101010101010 1010101......1010101......

    有点意思。

    其实也很容易能从 dpdp 中发现这个规律,每当 nn 为奇数时++++,就会使每隔 11+1+1

    这也不太好办。n=1e5n=1e5 时,这个 22 进制数就有 1e51e5 位。1010 进制的高精位数只知道比 1e51e5 小却没有办法确定。隔一位一个 11 也不方便化成 1010 进制啊。不过好像没有什么好办法能直接从 22 进制的高精转化为 1010 进制的高精。(仅为思考过程)

    能不能直接从 1010 进制的高精推过来呢?

    如果是二进制表示是 1000000....1000000.... ,它就可以轻松地表示为 2n2^n 然后用快速幂做了。

    那么现在考虑对这个 22 进制数 ×3×3 。哦不对,是 1111 。我们来看变成了什么。。

    1111 110110 11111111 1111011110 111111111111 1111110......1111110 ......

    这就可以说是非常显然了吧。( +1+1+2+2 变成 10000...10000... )

    写出来也就是其他题解中大佬们的公式。只不过我用了这种另类思路得到。

    可是有一个问题。 多项式乘法是 n2n^2 的。即便有快速幂,它的复杂度也是 n2lognn^2logn 的。

    那么就写一个 FFTFFT 加速一下多项式乘法就行啦!

    然后你要感谢你看到了这篇题解。如果你是那种对复杂度要求严格,认为复杂度决定一切和是否ACAC的选手,你可以少写一个FFTFFT

    n2lognn^2lognn2n^2nn 是什么?是数据位数。

    首先当 nn1e51e5 时你的 22 进制数是 1e51e5 位的。如果它变成 1010 进制,可以变成 Xe4Xe4 级别。如果再对它压一下位直接 1e81e8 进制,它可以变成 Xe3Xe3 级别。复杂度瞬间变成O(O(可过))

    实际上当 n=1e5n=1e5 时最后的答案压位后只有 37623762 位。

    而且另外一点,普通的相乘常数可是比 FFTFFT 小了不止几倍。也就是说如果你用了 FFTFFT 去"优化"它,你反而会更慢。

    FFTFFT + 小数相乘时暴力的优化 == 132ms132ms

    压位爆乘 + 输出优化 + 开小内存 == 8ms8ms

    伤感的故事。

    #include <bits/stdc++.h>
    #define rap(i,s,n) for(int i=s;i<=n;i++)
    #define drap(i,n,s) for(int i=n;i>=s;i--)
    #define N 5111
    #define Q 100000000
    #define ll long long
    #define m(s,k) memset(s,k,sizeof s)
    char xA[1<<16],xZ[20]; int xC=-1,xzz=0;
    inline void wt_z(){fwrite(xA,1,xC+1,stdout),xC=-1;}
    template<class T>inline void wt(T x,int t){
        if(xC>(1<<15)) wt_z();
        while(xZ[++xzz]=(char)(x%10+'0'),(x/=10)||(t>0)) --t;
        while(xA[++xC]=xZ[xzz],--xzz);
    }
    //得益于luogu的代码公开计划我可以愉快地抄大佬的快输板子了(不算抄袭吧QAQ)
    using namespace std;
    ll res[N],a[N],d[N];
    int sz1,sz2;
    int cheng(ll *a,int n,ll *b,int m){
        m(d,0); rap(i,0,n) rap(j,0,m) d[i+j]+=a[i]*b[j];
        rap(i,0,n+m) d[i+1]+=d[i]/Q,d[i]%=Q;
        int t=n+m+1; while(d[t]) d[t+1]+=d[t]/Q,d[t]%=Q,t++; t--;
        rap(i,0,t) a[i]=d[i]; return t;
    }
    //非常暴力又写的不是一般难看的乘
    int main(){
        int n,m; scanf("%d",&m); rap(i,1,m){
            scanf("%d",&n); int t=n+1;
            m(res,0); res[0]=1; m(a,0); a[0]=2; sz1=sz2=0;
            while(t){
                if(t&1) sz1=cheng(res,sz1,a,sz2); t>>=1;
                if(t) sz2=cheng(a,sz2,a,sz2);
            }
            if(n&1) res[0]++; res[0]-=2; if(res[0]<0) res[0]+=Q,res[1]--;
            ll k=0; drap(i,sz1,0){k=k*Q+res[i]; res[i]=k/3; k%=3;}
            while(res[sz1]==0) sz1--;
            wt(res[sz1],0); drap(i,sz1-1,0) wt(res[i],7); xA[++xC]='\n'; wt_z();
        }
        return 0;
    }
    

    当我知道暴力可以过,而且快的飞起的时候,我就好像看到了岩浆里燃烧的钻石,就好像看到了3滴血跑路的盖伦,就好像看到了我被一个就是破不了防的血条里只剩下真空的妖梦反杀。

    别和我提python.

    • 1

    信息

    ID
    3427
    时间
    1000ms
    内存
    500MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者