Fork me on GitHub

CF1080D Olya and magical square

CF1080D Olya and magical square\

题目链接:CF1080

 

这是一道很值得探究的数论找规律题(虽然大多数论都是找规律题)

为了简化题目,我们将所走的路径都放到正方形的边缘上

性质一:如果 $n>31$,那么我们可以对整个正方形切割一次,再对右下角的正方形随意切割,显然右下角的正方形的能够被切割的次数一定不小于 $10^{18}$

因此当 $n>31$ 时直接输出 $YES$ 和 $n-1$ 即可!

对于 $1\leqslant 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",n-1);
30         else
31         {
32             int    ans=check (n,k);
33             if (ans<0) puts("NO");
34             else printf("YES %d\n",ans);
35         }
36     }
37     return 0;
38 }

 

posted @ 2018-12-06 08:29  Paul·Shi  阅读(336)  评论(0编辑  收藏  举报