洛谷P1936 水晶灯火灵 P1775 古代人的难题_NOI导刊2010提高(02)【重题请做P1936】
首先我要说明,此题(古代人的难题)与水晶灯火灵是一模一样的!
古代人的难题
(File IO): input:puzzle.in output:puzzle.out
时间限制: 1000 ms 空间限制: 60000 KB 具体限制
Time to Submit: 01:57:40
题目描述
门打开了, 里面果然是个很大的厅堂。但可惜厅堂内除了中央的一张羊皮纸和一根精致的石笔,还有周围几具骷髅外什么也没有。 难道这就是王室的遗产? 小 FF 不信,他仔细阅读了羊皮纸上的内容后发现,里面书写的古代人一直没能解出的难题, 解除这道题目的人只要将答案用石笔写到这张羊皮纸上就能到达王室的宝藏室了。而当小 FF 拿起石笔后,刚刚打开的巨石门突然关上了。 这时小 FF 意识到原来那几具骷髅是在他之前到这里的冒险者,恐怕是因为没能破解这道题而困死在这里了。 小 FF 越想越害怕, 急忙联系到了你,为了能保命,他甚至愿意和你五五分……看来你不得不再次帮他了。 羊皮纸上的问题如下:
已知 x, y 为整数,且满足以下两个条件:
1. x, y ϵ [1..k], 且x,y,k ϵ Z;
2. (x^2 – xy – y^2)^2 = 1
给你一个整数 k, 求一组满足上述条件的 x, y 并且使得 x^2 + y^2 的值最大。
当小 F 得到答案后, 用石笔将答案书写在羊皮纸上,那么就能到达王室的遗产所在地了。
输入
一个整数 k
输出
输出文件仅一行,两个整数;
两个整数分别表示 x 和 y。x, y 之间用一个空格隔开。
样例输入
1995
样例输出
1597 987
数据范围限制
对于 30%的数据: 2<=k<=10^4.
对于 100%的数据: 2<=k<=10^18.
提示
Z是数学里面整数集合符号, 即x y k都是整数
Solution(P1775&P1936)
悄悄地打个表(其实就是在暴力枚举模拟的过程)
table_code
#include<bits/stdc++.h> using namespace std; unsigned long long k; int main() { freopen("table.txt","w",stdout); // cin>>k; int maxans=1,maxx=1,maxy=1; for(k=2;k<=10000;k++) { for(int x=1;x<=k;x++) for(int y=1;y<=x;y++) { if((x+y)*(x-y)==x*y+1||(x+y)*(x-y)==x*y-1) if(maxans<x*x+y*y) { maxans=max(maxans,x*x+y*y); maxx=x; maxy=y; } } cout<<k<<" "<<maxx<<" "<<maxy<<endl;} return 0; }
table.txt
k x y 2 2 1 3 3 2 4 3 2 5 5 3 6 5 3 7 5 3 8 8 5 9 8 5 10 8 5 11 8 5 12 8 5 13 13 8 14 13 8 15 13 8 16 13 8 17 13 8 18 13 8 19 13 8 20 13 8 21 21 13 22 21 13 23 21 13 24 21 13 25 21 13 26 21 13 27 21 13 28 21 13 29 21 13 30 21 13 31 21 13 32 21 13 33 21 13 34 34 21 35 34 21 36 34 21 37 34 21 38 34 21 39 34 21 40 34 21 41 34 21 42 34 21 43 34 21 44 34 21 45 34 21 46 34 21 47 34 21 48 34 21 49 34 21 50 34 21 51 34 21 52 34 21 53 34 21 54 34 21 55 55 34 56 55 34 57 55 34 58 55 34 59 55 34 60 55 34 61 55 34 62 55 34 63 55 34 64 55 34 65 55 34 66 55 34 67 55 34 68 55 34 69 55 34 70 55 34 71 55 34 72 55 34 73 55 34 74 55 34 75 55 34 76 55 34 77 55 34 78 55 34 79 55 34 80 55 34 81 55 34 82 55 34 83 55 34 84 55 34 85 55 34 86 55 34 87 55 34 88 55 34 89 89 55 90 89 55 91 89 55 92 89 55 93 89 55 94 89 55 95 89 55 96 89 55 97 89 55 98 89 55 99 89 55 100 89 55
哈,这不是熟悉的斐波那契数列兄弟嘛
那么问题就变成了:
已知k,求x,y。
其中x,y属于斐波那契数列相邻了两项且x>y(P1936 水晶灯火灵 中是m<n)
使得k>=x&&k<x+y
//文末有证明!
Code(P1775)
1 #include<bits/stdc++.h> 2 using namespace std; 3 unsigned long long k; 4 void make() 5 { 6 int i=0; 7 unsigned long long x=1,y=0,t,l=0,r; 8 while(true) 9 { 10 t=x; 11 x=x+y; 12 y=t; 13 if(k>=x&&k<x+y) 14 { 15 cout<<x<<" "<<y; 16 return; 17 } 18 } 19 return; 20 } 21 int main() 22 { 23 // freopen("puzzle.in","r",stdin); 24 // freopen("puzzle.out","w",stdout); 25 cin>>k; 26 make(); 27 return 0; 28 } 29 /* 30 1. x, y sy [1..k], 且x,y,k sy Z; 31 2. (x^2 - xy - y^2)^2 = 1 32 给你一个整数 k, 33 求一组满足上述条件的 x, y 34 并且使得 x^2 + y^2 的值最大。 35 36 */
也可以利用打的表(修改了一下)
1 #include<bits/stdc++.h> 2 using namespace std; 3 unsigned long long k; 4 unsigned long long table[300]={ 5 1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269, 6 2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903, 7 2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879, 8 956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141, 9 117669030460994,190392490709135,308061521170129,498454011879264,806515533049393,1304969544928657,2111485077978050,3416454622906707,5527939700884757, 10 8944394323791464,14472334024676221,23416728348467685,37889062373143906,61305790721611591,99194853094755497,160500643816367088,259695496911122585, 11 420196140727489673,679891637638612258,1100087778366101931}; 12 int main() 13 { 14 // freopen("puzzle.in","r",stdin); 15 // freopen("puzzle.out","w",stdout); 16 cin>>k; 17 for(int i=1;i<=300;i++) 18 if(k>=table[i]&&k<table[i+1]) 19 { 20 cout<<table[i]<<" "<<table[i-1]; 21 break; 22 } 23 return 0; 24 }
但是请注意,上面这种方法请在 工具 -> 编译选项 -> 代码生成/优化 -> 代码警告 中把“忽略所有警告信息” 设为“Yes”
Code(P1936)
1 #include<bits/stdc++.h> 2 using namespace std; 3 unsigned long long k; 4 void make() 5 { 6 int i=0; 7 unsigned long long x=1,y=0,t,l=0,r; 8 while(x<k*10) 9 { 10 t=x; 11 x=x+y; 12 y=t; 13 if(k>=x&&k<x+y) 14 { 15 cout<<"m="<<y<<endl<<"n="<<x; 16 return; 17 } 18 } 19 return; 20 } 21 int main() 22 { 23 cin>>k; 24 make(); 25 return 0; 26 } 27 /* 28 1. x, y sy [1..k], 且x,y,k sy Z; 29 2. (x^2 - xy - y^2)^2 = 1 30 给你一个整数 k, 31 求一组满足上述条件的 x, y 32 并且使得 x^2 + y^2 的值最大。 33 34 */
证明
本文提供两种证明方法。敬请过目~
证明(P1775)
(x^2 - xy - y^2)^2
= (y^2 + xy - x^2)^2
= [(x+y)^2 - xy - 2*x^2]^2
=[(x+y)^2 - (x+y)*x - x^2]^2
由上式可知, 如果x, y 满足条件2, 那么x+y, y 也满足条件2。
那么Fibomacci 中小于等于k 的最大两个相邻的数即为试题所需的解。
证明(P1936)
记f(n,m)=(n^2-mn-m^2)^2
则有f(m+n,m)=[(m+n)^2-n(m+n)-n^2]^2=(m^2+mn-n^2)^2=(n^2-mn-m^2)^2=f(n,m)
易得f(1,1)=1
故1=f(1,1)=f(2,1)=f(3,2)=...