CF1080D Olya and magical square
题目链接:CF1080
这是一道很值得探究的数论找规律题(虽然大多数论都是找规律题)
为了简化题目,我们将所走的路径都放到正方形的边缘上
性质一:如果 $n>31$,那么我们可以对整个正方形切割一次,再对右下角的正方形随意切割,显然右下角的正方形的能够被切割的次数一定不小于 $10^{18}$。
因此当 $n>31$ 时直接输出 $YES$ 和 $n-1$ 即可!
对于 $1leqslant n leqslant 31$ 的情况,我们枚举路径上的正方形的边长 $2^{i}$,计算出最少的切割次数 $L$ 和最多的切割次数 $R$,可以证明 $[L,R]$ 这个区间内的所有切割次数都可以被构造出来。
如何计算最少的切割次数:考虑只切割出我们要走的路径的格子。每次只对边缘那一圈的格子切割,第一次需要切割 $1$ 次,第二次需要切割 $3$ 次,第三次需要切割 $7$ 次……
因此最少的切割次数为 $sum_{j=1}^{n-i}2^j-1$.。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int t; 5 ll pw[35]; 6 int check (int n,ll k) 7 { 8 for (int i=0;i<n;i++) 9 { 10 int p=n-i; 11 ll l=0; 12 for (int j=1;j<=p;++j) l+=(1LL<<j)-1; 13 if (l>k) continue; 14 long long r=pw[n]-((1LL<<(p+1))-1)*pw[i]; 15 if (r<k) continue; 16 return i; 17 } 18 return -1; 19 } 20 int main() 21 { 22 scanf ("%d",&t); 23 for (int i=1;i<=32;++i) pw[i]=4LL*pw[i-1]+1; 24 while (t--) 25 { 26 int n; 27 long long k; 28 scanf ("%d %lld",&n,&k); 29 if (n>31) printf ("YES %d ",n-1); 30 else 31 { 32 int ans=check (n,k); 33 if (ans<0) puts("NO"); 34 else printf("YES %d ",ans); 35 } 36 } 37 return 0; 38 }