1 条题解

  • 0
    @ 2025-8-24 22:18:55

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar tx344
    AFOer

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

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

    以下是正文


    [eJOI2019] 塔

    题面

    从序列中选择一段连续序列,将序列和加入序列,求最小操作次数生成 nn

    分析

    初看感觉没什么思路

    1. 先考虑每次操作都选择整个序列

    多次操作后序列为:

    1,1,2,4,8,16,32,64,1,1,2,4,8,16,32,64,……

    我们能发现 ai=2i2 (i>1)a_i=2^{i-2}\ (i>1)

    2. 试着对于某次操作不选择整个序列

    随便选择一次操作,

    1,1,2,4,7,15,30,60,1,1,2,4,\color{red}7\color{q},15,30,60,……

    这个序列只是将原序列中的 88(即第 44 次操作)变为:

    a2+a3+a4=1+2+4=7a_2+a_3+a_4=1+2+4=7

    后面的操作还是选择整个序列

    我们发现,当 a5a_5 减少了 11a6+ia_{6+i} 就会减少 2i2^i

    换句话说,当 ani1a_{n-i-1} 减少了 11ana_n 就能减少 2i2^i

    那么我们是不是可以nn 以前的某些数减少 11(即不选择 a1a_1)就可以让 ana_n 变为我们想要的数。

    所以我们对于任意一次操作,只用考虑从 a1a_1a2a_2 开始选择整个序列

    1,1,2,4,8,16,32,64,128,1,1,2,4,8,16,32,64,128,……

    3. 实现

    例如:

    我们要得到 5959,那么肯定使 6464 变为 5959 最优。

    6464 变为 5959 就要让 6464 减少 55

    等同于让 6464 减少 (22+20)(2^2+2^0)

    所以从 6464 往前看,只要让第 4466 次操作都不选择整个序列(即不选择 a1a_1),而其他操作还是选择整个序列就可以得到 5959

    1,1,2,4,7,15,29,591,1,2,4,7,15,29,59

    所以我们先让每次操作都选择整个序列,对于要得到的数 qq,只用先求出将哪个数变成 qq,再将 2tq2^t-q 二进制分解一下,确定哪几次操作不选择 a1a_1

    4. 代码

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    int T,n,m,now,t,ans[70];
    signed main()
    {
    //	freopen("tower.in","r",stdin);
    //	freopen("tower.out","w",stdout);
    	scanf("%lld",&T);
    	while(T--)
    	{
    		scanf("%lld",&n);m=1;
    		if(n==1){puts("0");continue;}
    		t=1;ans[1]=1;
    		while(m<n)
    		{
    			t++;
    			ans[t]=1;
    			m<<=1;
    		}
    		n=m-n;
    		now=t-1;
    		printf("%d\n",t);
    		while(n)
    		{
    			if(n&1)ans[now]=2;
    			now--;
    			n>>=1;
    		}
    		for(int i=1;i<=t;i++)printf("%d %d\n",ans[i],i);
    	}
    }
    
    • 1

    信息

    ID
    5277
    时间
    2000ms
    内存
    100MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者