P8913 题解
xiaoqian02 · · 题解
第一部分:思路
首先明确一下,这题是构造题。
限制很宽泛,构造也就很憨批。——选自 P8846
不过,这道题的构造没 P8846 憨批,还是要多用点脑子的。
第一步:构造
首先,一定要有
第一个是
同理,接下来是
所以规律出来了:每组
但是,如果直接这样会全 WA 掉。因为
有两种方法:一是把它扔了(剩下加起来还有
这样,构造部分就完成了。
第二步:判断正负号
这一部分比较麻烦,但我们可以先做一点处理。
因为
-
如果加这个数,则输出
++。 -
如果减这个数,则输出
--。 -
如果不使用这个数,则输出
+-(或者-+也可以)。
实际上,用
接下来,就是怎么排的问题。有一种巧妙的方法:三进制。但是这种三进制比较特殊。
首先,将
然后,从个位开始看每一位。
-
先加上下面传上来的进位(具体进位机制在下面)。
-
如果当前位为
0 ,说明这个数不用。 -
如果当前位为
1 ,说明加这个数。 -
如果当前位为
2 ,这意味着要用2 个,但是我们只有一个数。考虑将当前位设为-1 ,向上进位。这也等同于减去这个数再加上这个数的3 倍,符合要求。 -
最后,如果当前位为
3 ,同样向上进位,并将当前位设为0 。
对于每一位,按上面的规则对应输出即可。
这样,这道题就解决了。
第二部分:代码
#include<bits/stdc++.h>
using namespace std;
void IOS()//cin 优化
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
typedef long long ll;//开 long long 保险一点
ll m,q,p;
ll pw3[25];//存储 3 的幂次
int main()
{
IOS();
cin>>m>>q;
pw3[1]=1;
for(ll i=2;i<=20;i++) pw3[i]=3*pw3[i-1];
cout<<40<<endl;
for(ll i=1;i<=40;i++)
cout<<min(pw3[(i+1)>>1],(ll)(1000000000))<<" ";
//这里用的是第二种方法,第一种方法就是只构造 38 个数
cout<<endl;
while(q--)
{
cin>>p;
ll ad=0;//ad 存进位
p/=2;
for(ll i=1;i<=20;i++)
{
ll kkk=p%3+ad;
ad=0;
if(kkk==2)
{
kkk=-1;
ad=1;
}
if(kkk==3)
{
kkk=0;
ad=1;
}
if(kkk==-1) cout<<"--";//减去
else if(kkk==0) cout<<"+-";//不用
else cout<<"++";//加上
p/=3;
}
cout<<endl;
}
return 0;
}