【2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest D】【脑洞 构造】Distribution in Metagonia 把数以2^p3^
2015-11-15 20:46
555 查看
#include<stdio.h> #include<iostream> #include<string.h> #include<ctype.h> #include<math.h> #include<map> #include<set> #include<vector> #include<queue> #include<string> #include<algorithm> #include<time.h> #include<bitset> using namespace std; #define MS(x,y) memset(x,y,sizeof(x)) #define MC(x,y) memcpy(x,y,sizeof(x)) #define MP(x,y) make_pair(x,y) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T> inline void gmax(T &a,T b){if(b>a)a=b;} template <class T> inline void gmin(T &a,T b){if(b<a)a=b;} const int N=1e5+1e4,M=0,Z=1e9+7,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;const double eps=1e-8,PI=acos(-1.0);//.0 void fre() { freopen("distribution.in","r",stdin); freopen("distribution.out","w",stdout); } int casenum,casei; LL n,m; LL a[1000]; void solve(LL n,LL mul) { while(n%2==0) { n/=2; mul*=2; } while(n%3==0) { n/=3; mul*=3; } if(n==1)a[++m]=mul; else { LL x;for(x=3;x*3<n;x*=3); a[++m]=mul*x; solve(n-x,mul); } } int main() { fre(); scanf("%d",&casenum); for(casei=1;casei<=casenum;casei++) { scanf("%lld",&n);m=0; solve(n,1); printf("%lld\n",m); for(int i=1;i<=m;i++)printf("%lld ",a[i]); puts(""); } } /* 【trick&&吐槽】 还是那句话,构造题先构造数据找规律。 【题意】 T([1,1000]组数据), 对于每组数据,给你一个数n([1,1e18]), 让你把n拆成若干个数(m个数,m是正整数)之和的形式, 使得这m个数都是2^p*3^q这样的形式,因子中只有2和3,而且相互之间不是倍数关系。 并输出。 【类型】 构造 【分析】 遇到构造题,很难有头绪的时候,我们可以首先构造小数据来猜解。 在小数据的构造中,我们感觉,对于所有的数都有构造方案。于是—— 操作1,我们发现,如果一开始的n可以表示成n=2^p*3^q*w的形式, 那么我们直接使得n/=(2^p*3^q),然后对于w进行构造即可。 为什么这样子可以呢?因为我们对于w可能还有数的拆分, 而拆分成的若干个数,都含有2^p*3^q。 所以只要w被拆分成的若干个数之间不相互是倍数关系,那最后就不会出现倍数关系 2,然后现在我们要处理w啦。 w中是不含有任何因子2和因子3的,既然如此w就必定为奇数。 如果w为1,那么说明w已经满足目标条件了,我们直接输出即可。 如果w不为1,那么我们执行以下的操作。 找到一个最大的数v,使得v=3^p且v<w。 为什么会产生这种思路呢?很简单,因为我们最简单的拆分方案就是只拆分成2的若干次方或3的若干次方。 而这里拆分出一个3^p,必然使得剩下的数是2的倍数 3,经过之前这两步,我们相当于把初始的n,拆成了mul0*(A+B),其中A是能拆分的最大3的次方,B是偶数。 A必然不是B的倍数,因为A是3的次方,是奇数,而B却是偶数; 同时B必然不是A的倍数,因为如果B是A的倍数,那至少为2倍,那就不符合A是能拆分的最大3的次方这一条件。 然而B不一定恰好是符合要求的拆分数。这意味着B还要继续拆分下去。然而B一定是偶数,至少含有一个因子2, 这样我们先把B中的2和3提取出来是,使得可以写成mul0*(A+mul1*(B+C))之类的形式。 这时,B和C中比A至少多含有一个2,所以A一定不是B和C的倍数,而且A也不是C的继续拆分数的倍数。 同时,因为A是能拆分的最大3的次方的性质,所以B和C以及其继续拆分的数也不会是A的倍数。 重复这个过程下去,因为每次都是拆分成3的最大次方+偶数,所以拆分一定可以最终完成,得到最后的结果。 【时间复杂度&&优化】 O(Tlogn) */
相关文章推荐
- jQuery入门 构造函数
- Python类方法__init__和__del__构造、析构过程分析
- 简单的四则运算
- 数的奇偶性
- 关于获得ArrayAdapter对象的细节
- ACM网址
- 1272 小希的迷宫
- 1272 小希的迷宫
- hdu 1250 大数相加并用数组储存
- 类的继承与派生
- 矩阵的乘法操作
- 探讨“临时对象”(temporary object)
- 蚂蚁爬行问题
- 蚂蚁爬行问题
- 求两个数的最大公约数【ACM基础题】
- 打印出二进制中所有1的位置
- 杭电题目---一只小蜜蜂
- HDOJ 1002 A + B Problem II (Big Numbers Addition)
- 初学ACM - 半数集(Half Set)问题 NOJ 1010 / FOJ 1207
- 初学ACM - 组合数学基础题目PKU 1833