题目大意:
一个房间里有n盏灯泡,一开始都是熄着的,有1到n个时刻,每个时刻i,我们会将i的倍数的灯泡改变状态(即原本开着的现将它熄灭,原本熄灭的现将它点亮),问最后有多少盏灯泡是亮着的。
40%的数据保证,n<=maxlongint
100%的数据保证,n<=10^200
题解:
规律可得:
ans[n]为sqrt(n)向下取整。
问题是高精度:
看了一个个大数开方,表示一脸懵逼,后来发现有个水法……貌似很有效。
1.因为sqrt(n)的位数在1~ X/2+1之间,X为N的位数,所以枚举,怎么枚举呢。
(1)首先考虑答案位数为,因为位数最多只有X/2+1位,所以直接设答案有X/2+1位枚举,到时候高位去0。
(2)最高位枚举到个位,从9开始枚举到1,后面的数位补0,构成一个数,若这个数的平方大于N就继续继续枚举这个数位,不然退出,枚举下一个数位。
(3)如果枚举完都没有找到平方不大于N的就代表答案的位数远远没有X/2+1那么多,那就这位赋值为0,到时候高位去0。
注意枚举的时候求平方要用高精度,不然嘿嘿你懂滴。
~这是一个比高精度之大数开方要简单的方法~
const
maxn=501;
var
a,c:array [0..maxn] of longint;
ans,s:string;
p,lx,i,k:longint;
j:char;
function check(ds:string):boolean;
var
i,j,x:longint;
q:string;
begin
fillchar(a,sizeof(a),0);
fillchar(c,sizeof(c),0);
q:='';
for i:=1 to lx do
a[lx-i+1]:=ord(ds[i])-48;
for i:=1 to lx do
begin
x:=0;
for j:=1 to lx do
begin
c[i+j-1]:=a[i]*a[j]+x+c[i+j-1];
x:=c[i+j-1] div 10;
c[i+j-1]:=c[i+j-1] mod 10;
end;
c[i+j]:=x;
end;
i:=lx*2;
while (c[i]=0) and (i>1) do dec(i);
for j:=i downto 1 do
q:=q+chr(c[j]+48);
if ((length(q)=length(s)) and (q>s))
or (length(q)>length(s)) then exit(true);
exit(false);
end;
begin
readln(s);
lx:=length(s) div 2+1;
for i:=1 to lx do ans:=ans+'0';
for i:=1 to lx do
for j:='9' downto '0' do
begin
ans[i]:=j;
if check(ans)=false then break;
end;
i:=1;
while (ans[i]='0') and (i<>lx) do inc(i);
for k:=i to lx do write(ans[k]);
end.