jzoj P2434 【普及_模拟】开关灯泡

题目大意:
一个房间里有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.
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值