【思路】
数学+高精度。
分析题目:题中有言,i时刻将其所有倍数的灯熄灭,由此得知一个数有多少个倍数就会被操作多少次,因为初始全部熄灭,所以操作数为奇的灯最后会亮着,再进一步,只有序号为平方数的灯在最后会亮着。
由此题目转化为求n以内平方数的个数,个数为sqrt(n)个(别问我怎么知道的=_=)
数据范围要求我们用到高精。至此,题目就是对一个大数开方的问题,NOIP的初赛曾出现过这个程序。
【代码】
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 using namespace std; 5 6 const int maxn = 200+10; 7 struct Bign{ 8 int len; 9 int num[maxn]; 10 Bign() { memset(num,0,sizeof(num)); } 11 }; 12 13 Bign goal; 14 15 Bign times(Bign a,Bign b) { 16 Bign c; 17 c.len=a.len+b.len+2; 18 for(int i=0;i<a.len;i++) 19 for(int j=0;j<b.len;j++) 20 c.num[i+j] += a.num[i]*b.num[j]; 21 for(int i=0;i<c.len-1;i++) { 22 c.num[i+1] += c.num[i]/10; 23 c.num[i] %= 10; 24 } 25 while(c.num[c.len-1]==0) c.len--; 26 return c; 27 } 28 29 Bign average(Bign a,Bign b) { 30 Bign c; c.len=max(a.len,b.len); 31 for(int i=0;i<c.len;i++) { 32 c.num[i] += a.num[i]+b.num[i]; 33 c.num[i+1] += c.num[i]/10; 34 c.num[i] %= 10; 35 } 36 37 if(c.num[c.len]) c.len++; 38 for(int i=c.len-1;i;i--) { 39 c.num[i-1] += (c.num[i]%2) *10; 40 c.num[i] /= 2; 41 } 42 c.num[0]/=2; 43 if(c.num[c.len-1]==0) c.len--; 44 return c; 45 } 46 47 Bign plustwo(Bign a) { 48 a.num[0] += 2; 49 int i=0; 50 while(i<a.len && a.num[i]>=10) { 51 a.num[i+1] += a.num[i]/10; 52 a.num[i] %= 10; 53 i++; 54 } 55 if(a.num[a.len]) a.len++; 56 return a; 57 } 58 59 bool over(Bign a,Bign b) { 60 if(a.len>b.len) return true; 61 else if(a.len<b.len) return false; 62 63 for(int i=a.len;i>=0;i--) //倒序 64 if(a.num[i]>b.num[i]) return true; 65 else if(a.num[i]<b.num[i]) return false; 66 67 return false; 68 } 69 70 int main() { 71 ios::sync_with_stdio(false); 72 string s; 73 cin>>s; 74 goal.len=s.size(); 75 for(int i=0;i<goal.len;i++) goal.num[i]=s[goal.len-1-i]-‘0‘; 76 Bign L , R=goal , M; 77 L.len=1; L.num[0]=1; 78 do 79 { 80 M=average(L,R); 81 if(over(times(M,M),goal)) R=M; 82 else L=M; 83 } while(! over(plustwo(L),R)) ; 84 for(int i=L.len-1;i>=0;i--) cout<<L.num[i]; 85 return 0; 86 }
时间: 2024-11-08 23:53:30