1 条题解

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

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 2020HZ06
    **

    搬运于2025-08-24 22:25:57,当前版本为作者最后更新于2024-10-29 21:08:12,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    本篇题解参考 https://www.cnblogs.com/vb4896/p/9489338.html 在此致谢。

    注意拆分后得到的数会去重。因此有一个方案是假设 nnss 位而其中有 tt11。那么可以每次拆出 lowbit(n)\operatorname{lowbit(n)} 并让 nlowbit(n)nn-\operatorname{lowbit(n)}\to n。拆成若干 2k2^k 之后从最高位不停 /2/2 并去重最终即可达到 11。代价 s+t2s+t-2。这是答案的上界

    这个过程可以视作加法链ai=aj+ak(j,k<i),a0=1,am=na_i=a_j+a_k(j,k<i),a_0=1,a_m=n,求最短加法链长度 mm

    然而有时候不是这样。15=(1111)215=(1111)_2[1,2,3,6,9,15][1,2,3,6,9,15] 加法链长度只有 s+t3=5s+t-3=5。而 s+t2=4+42=6s+t-2=4+4-2=6

    现在有两条性质:

    • aiai+12a_i\ge \frac{a_{i+1}}2,显然。不然 aia_i 拼不出来。
    • ai2it+1a_i\ge 2^{i-t+1}。因为 ms+t2m \le s+t-2。得到 mt+1s1m-t+1\le s-1,又因为 am=n2s1a_m=n\ge 2^{s-1},两边同时作为指数,得到 am2mt+1a_m\ge 2^{m-t+1},由性质一得 ai2it+1a_i\ge 2^{i-t+1}t4t\le 4ai2i3a_i\ge 2^{i-3}

    考虑 m=s+t2m=s+t-2 可以直接构造,只需搜索 ms+t3m\le s+t-3 的情况即可。类似的有 ai2it+22i2a_i\ge 2^{i-t+2}\ge 2^{i-2}。直接搜即可。

    接下来有几种搜索方法:

    方法一:每组数据搜索,枚举 i+1i+1 位置填什么,最优性和可行性剪枝。

    很遗憾,

    1
    13 17 19 20
    

    直接能把它卡 T 飞。

    方法二:枚举值域太傻,枚举当前链中元素暴力组合。由于元素是 O(logn)O(\log n) 量级,单组数据能很快出解。

    然而 T=500T=500 会导致 TLE on test 2。

    方法三:只进行一次 DFS 预处理出所有数的答案。注意 nn11 的个数不超过 44。另外还可以发现一条性质:

    每次往链中加元素时 ai=ai1+ak(k<i)a_i=a_{i-1}+a_k(k<i) 一定成立。因为 ai1a_{i-1} 如果拼出来却暂时不用完全可以到后面用到再拼

    举个例子,假设现在链中元素 1,21,2。要拼出 77,一种方案是 [1,2,3,4,7](7=3+4,4=2+2,3=1+2)[1,2,3,4,7](7=3+4,4=2+2,3=1+2)。但是我们也可以 [1,2,4,6,7],(4=2+2,6=2+4,7=6+1)[1,2,4,6,7],(4=2+2,6=2+4,7=6+1)。也就是说,ai1=x+ya_{i-1}=x+yaj+ai1=ak(i1<j<k)a_j+a_{i-1}=a_k(i-1<j<k) 完全可以把 x,yx,y 的累加贡献后移变成 (aj+x)+y=ak(a_j+x)+y=a_k,次数不变。

    因此直接枚举 aj+ai1(j<i)a_j+a_{i-1}(j<i) 扩展即可。只需一重循环。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long 
    #define pb push_back
    int T,d1,d2,d3,d4,n,s,t;
    int a[35];
    vector<int>ans[4*(1<<20)+5],v;
    void dfs(int nw){
    	if(nw>=25||(nw>=2&&a[nw]<(1<<nw-2))) return;//24=max(s+t-3)=23+4-3
    	if(__builtin_popcount(a[nw])<=4&&(!ans[a[nw]].size()||ans[a[nw]].size()>nw)){//更新答案
    		ans[a[nw]].clear();
    		for(int i=0;i<=nw;i++) ans[a[nw]].pb(a[i]);
    	}
    	for(int i=0;i<=nw;i++){//扩展
    		a[nw+1]=a[nw]+a[i];
    		if(a[nw+1]<=(1<<22)) dfs(nw+1);
    		else break;
    	}
    }
    int main(){
    	scanf("%d",&T);
    	a[0]=1;
    	dfs(0);
    	for(int i=1;i<=(1<<22);i++){
    		if(__builtin_popcount(i)<=4&&!ans[i].size()){//答案为 s+t-2
    			for(int j=0;(1<<j)<=i;j++) ans[i].pb(1<<j);
    			v.clear();
    			int u=i;
    			while(u!=(u&-u)) v.pb(u),u-=(u&-u);
    			for(int j=v.size()-1;j>=0;j--) ans[i].pb(v[j]);//倒着插回去
    		}
    	}
    	while(T--){
    		scanf("%d%d%d%d",&d1,&d2,&d3,&d4);
    		n=(1<<d1)+(1<<d2)+(1<<d3)+(1<<d4);
    		printf("%d\n",ans[n].size()-1);
    		for(int i=ans[n].size()-1;i>0;i--) printf("%d %d %d\n",ans[n][i],ans[n][i-1],ans[n][i]-ans[n][i-1]);//直接相减构造答案
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    6182
    时间
    3000ms
    内存
    512MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者