题目传送门
题意:
有一个大小是的正方形,让你进行次操作。
有一种操作:选择一个的正方形,切割成个大小为的正方形,且不改变正方形的位置,即只画出分割线,看上去还是一个大小是的正方形。 并且 是偶数。
询问你是否能从左下角走到右上角,只能向上走和向右走,并且经过的正方形大小相同。
如果可以,设这些正方形的边长为,输出。
数据范围:,。
题解:
需要发现:当时,一定有解,且输出。画画图就知道了。
当时,任何合理的计算都不会爆,可以放心的计算。
分析的情况:
枚举路径上的正方形边长,可以发现以下等式成立时有解。
是路径上的正方形边长。
是路径上的正方形所需切割次数。
是切割整个正方形所需切割次数。
是将路径上的正方形切割至无法切割的状态所需的切割次数。
感受:
这道题第一次看到时想了一个小时做不出来。
现在第二次看到时想了两个小时想吐了,然后看了看题解的第一行(从知乎学习的看题解方法,看一行题解接着思考,思考不出再看一行,尽量多的思考),发现和自己想的思路差不多,于是硬着头皮接着搞出来了。
标签写着math的题我是真的不会啊。。。。。。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
ll qpow(ll x , ll y)
{
ll ans = 1 ;
while(y)
{
if(y & 1) ans *= x ;
x *= x , y >>= 1 ;
}
return ans ;
}
ll sum(ll x)
{
ll ans = 0 ;
for(ll i = 1 ; i <= x ; i ++)
ans += qpow(2 , (i - 1) * 2) ;
return ans ;
}
ll cal(ll x)
{
ll ans = 0 ;
for(ll i = 1 ; i <= x ; i ++) ans += qpow(2 , i) - 1 ;
return ans ;
}
int main()
{
int t ;
scanf("%d" , &t) ;
while(t --)
{
ll n , k ;
bool flag = 0 ;
int temp ;
scanf("%lld%lld" , &n , &k) ;
if(n >= 32){printf("YES %lld\n" , n - 1) ; continue ;}
ll sum1 = sum(n) ;
for(ll i = 1 ; i <= n ; i ++)
{
ll s = cal(i) ;
ll t = sum(n - i) * (qpow(2 , i + 1) - 1) ;
if(s <= k && k <= sum1 - t){flag = 1 , temp = n - i ; break ;}
}
if(flag) printf("YES %d\n" , temp) ;
else printf("NO\n") ;
}
return 0 ;
}