很有趣的一个构造题,跟队友训练的时候,一直在考虑,通过k传送到k,设置断点,然后各区间乘法原理,斐波那契数列取项求和,乘积之类的想法,并不对。
有些显然的结论。
总的方案数等于,到达199的方案数,加上到达198的方案数。但是我们通过k传送到k,可以构造出后面的方案数均为空。
从k传送到k,则总方案不会计入到达该层方案数。
从k传送到199,则总方案会计入一倍到达该层方案。
从k传送到k+1,则到达k+1层的方案会累加入到达k层的方案。
我们发现上面的三种构造,拥有0,1和+(相同时即为2倍),所以我们考虑将n二进制拆分。
比如n为7,拆分成1,2,4。
1传送到199 总方案数0+1=1 从1开始的方案数 1 1 1 2 3.....
3传送到4 从1开始的方案数1 1 1 2 2.....
5传送到199 总方案数1+2=3 从1开始的方案数 1 1 1 2 2 2 2 4...
7传送到8 从1开始的方案数 1 1 1 2 2 2 2 4 4...
9传送199 总方案数3+4=7 从1开始的方案数 1 1 1 2 2 2 2 4 4
10传送到10 从1开始的方案数 1 1 1 2 2 2 2 4 4 4 0 0 0 0....起到封死的效果
再比如n为5,拆分成1,4。
1传送到199 总方案数0+1=1 从1开始的方案数 1 1 1 2 3....
3传送到4 从1开始的方案数 1 1 1 2 2...
5传送到5 从1开始的方案数 1 1 1 2 2 2 2 4...
7传送到8 从1开始的方案数 1 1 1 2 2 2 2 4 4...
传送199 总方案数1+4=5 从1开始的方案数 1 1 1 2 2 2 2 4 4
10传送到10 从1开始的方案数 1 1 1 2 2 2 2 4 4 4 0 0 0 0....起到封死的效果
可以看到传送门很有规律,在奇数个奇数时,用来增加当前2的某次方,或者增加0。在偶数个技术时,用来把2的次方翻倍。最后用一个传送门封死。
代码应该是对的,但是提交一直wa。试了些其他博客里的ac代码也都wa掉了。猜测评测机出锅。
1 #include <cstdio> 2 using namespace std; 3 typedef long long ll; 4 int ans,n; 5 int main() 6 { 7 while (scanf("%lld",&n) > 0) 8 { 9 if (n == 0) 10 { 11 printf("2 1 1 2 1 "); 12 continue; 13 } 14 ans = 0; 15 for (int i = 31;i >= 0;i--) 16 if (n & (1ll << i)) 17 { 18 ans = i; 19 break; 20 } 21 printf("%d ",(ans + 1) * 2); 22 for (int i = 0;i <= ans;i++) 23 { 24 if (n & (1ll << i)) 25 printf("%d 199 ",i * 4 + 1); 26 else 27 printf("%d %d ",i * 4 + 1,i * 4 + 1); 28 if (i != ans) 29 printf("%d %d ",i * 4 + 3,i * 4 + 4); 30 else 31 printf("%d %d ",i * 4 + 2,i * 4 + 2); 32 } 33 } 34 return 0; 35 }