天天看点

Vijos Oct.28 - NOIP2012模拟赛

      只做了第一题,得分100,有29人得分超过100,zzm140分,只有14个人比他高。这次比赛难度应该是比较大,应该把暴力写好,第三题30分还是比较好拿。第一题写的时间太长了。

A  进制转换

      小数转分数是百度搜的规律,应该多想一会。这题耽误很长时间,一直在纠结分数转二进制的时候哪个句子在哪个句子前边。还是思路不清楚的缘故。

      还有两个很好的思路。

      官方题解:不难发现,我们列方程的方法是将X的小数点向右移动若干位,移出两个正好错开了循环节长度为的小数,此时两个数相减,可以将循环部分消除,便可以解出方程。一般地,假设有p1位非循环位,非循环部分形成的十进制数是k1;有p2位循环节,循环节部分形成的十进制数是k2。

      可以得到方程:10^(p1+p2)*X-(10^p1)*X=(10^p2)k1+k2-k1。

      比较暴力的做法:直接模拟性价比较高,将十进制的循环部分扩增到1000位

然后不断*2,hash判重。

Codeprogram vijos1062A;
var i,a,b,c,t,cnta,tot,ans:longint;
    pos:array[0..1000000] of longint;
    s:array[0..1000000] of longint;
    ch:char;
function  GCD(a,b:longint):longint;
          var r:longint;
          begin
          repeat
            r:=a mod b;
            a:=b;b:=r;
          until r=0;
          exit(a);
          end;
begin 
read(ch);read(ch);read(ch);
while ch<>'(' do begin
  a:=a*10+ord(ch)-ord('0');
  inc(cnta);read(ch);end;
read(ch);b:=a;
while ch<>')' do begin
  b:=b*10+ord(ch)-ord('0');
  c:=c*10+9;
  read(ch);end;
for i:=1 to cnta do c:=c<<1+c<<3;
b:=b-a;t:=gcd(b,c);
b:=b div t;c:=c div t;
tot:=0;ans:=0;tot:=0;
//writeln(b,'/',c);
while pos[b]=0 do begin
  inc(tot);pos[b]:=tot;b:=b<<1;ans:=0;
  if b>=c then begin
               dec(b,c);
               ans:=1;
               end;
  s[tot]:=ans;
  end;
write('0.');
for i:=1 to pos[b]-1 do write(s[i]);
write('(');
for i:=pos[b] to tot do write(s[i]);
writeln(')');
//for i:=1 to tot do writeln(s[i]:5,pos[i]:5);
end.
      

  orzsjx的神模拟

Code
program T1062_1;
var s:string;
  n,m,i,j,k,mo,moo:longint;
  dn,dm,rec:array[0..1000000]of longint;
begin
  readln(s);write('0.');
  k:=pos('(',s);
  mo:=1;moo:=1;
  for i:=3 to k-1 do mo:=mo*10;
  for i:=k+1 to length(s)-1 do moo:=moo*10;
  if k>3 then val(copy(s,3,k-3),n,i);
  val(copy(s,k+1,length(s)-k-1),m,i);
  rec[0]:=0;
  dn[0]:=n;
  dm[0]:=m;
  if k>3 then
  begin
    for i:=1 to 1000000 do
    begin
      rec[i]:=dn[i-1]*2 div mo;
      dn[i]:=dn[i-1]*2 mod mo+dm[i-1]*2 div moo;
      dm[i]:=dm[i-1]*2 mod moo+dm[i-1]*2 div moo;
      for j:=0 to i do if (dn[i]=dn[j])and(dm[i]=dm[j]) then break;
      if j<>i then
        begin
        for k:=1 to j do write(rec[k]);
        write('(');
        for k:=j+1 to i do write(rec[k]);
        writeln(')');
        writeln;
        for k:=0 to i do
          writeln(rec[k]:5,dn[k]:5,dm[k]:5);
        halt;
        end;
    end;
  end else
  begin
    for i:=1 to 1000000 do
    begin
      rec[i]:=dm[i-1]*2 div moo;
      dm[i]:=dm[i-1]*2 div moo+dm[i-1]*2 mod moo;
      for j:=0 to i do if dm[i]=dm[j] then break;
      if i<>j then
      begin
        for k:=1 to j do write(rec[k]);
        write('(');
        for k:=j+1 to i do write(rec[k]);
        write(')');
        halt;
      end;
    end;
  end;
end.      

B 时区

      好神奇的题目,看了题解以后做的。发现一个人的时区确定了以后他前面的人的时区就有了上界,后面类似,每次找可选时区最少的搜索。

Code
VijosNT Mini 2.0.5.7 Special for Vijos 
编译通过... 
├ 测试数据 01:答案正确... (0ms, 700KB) 
├ 测试数据 02:答案正确... (0ms, 700KB) 
├ 测试数据 03:答案正确... (0ms, 700KB) 
├ 测试数据 04:运行超时... (?, 700KB) 
├ 测试数据 05:答案正确... (0ms, 700KB) 
├ 测试数据 06:答案正确... (0ms, 700KB) 
├ 测试数据 07:答案正确... (0ms, 700KB) 
├ 测试数据 08:答案正确... (0ms, 700KB) 
├ 测试数据 09:答案正确... (0ms, 700KB) 
├ 测试数据 10:答案正确... (0ms, 700KB) 
program vijos1749;
uses math;
const FileName='vijos1749';maxn=60;
var ans,t:array[0..maxn] of longint;
    a,n,i:longint;
function  upint(a,b:longint):longint;
          begin
          if a<=0 then exit(0)
                  else exit((a-1)div b+1);
          end;
procedure print;
          var i:longint;
          begin
          for i:=1 to n-1 do
            write(ans[i],' ');
          writeln(ans[n]);
          halt;
          end;
procedure DFS(k:longint;sq,ren:int64);
          var i,r,l,cnt,find:longint;
          begin
          if k>n then print;cnt:=n+1;
          for i:=1 to n do
            if(not boolean((ren>>i)and 1))
               then begin
                    l:=i;r:=i;
                    while( l>0 )and(not boolean((ren>>l)and 1))do dec(l);
                    while(r<n+1)and(not boolean((ren>>r)and 1))do inc(r);
                    if l<>0   then l:=upint((ans[l]*60+t[l]-t[i]),60)else l:=0;
                    if r<>n+1 then r:=   (ans[r]*60+t[r]-t[i])div 60 else r:=n-1;
                    if(r<0)or(l>n-1)or(l>r)then continue;
                    if min(r,n-1)-max(l,0)+1<cnt
                       then begin
                            cnt:=min(r,n-1)-max(l,0)+1;
                            find:=i;end;
                    end;
          l:=find;r:=find;if k=1 then find:=n>>1;if cnt=n+1 then exit;
          while( l>0 )and(not boolean((ren>>l)and 1))do dec(l);
          while(r<n+1)and(not boolean((ren>>r)and 1))do inc(r);
          if l>0   then l:=upint((ans[l]*60+t[l]-t[find]),60)else l:=0;
          if r<n+1 then r:=(ans[r]*60+t[r]-t[find])   div 60 else r:=n-1;
          //writeln(k:5,l:5,r:5,find:5,sq:5,ren:5);
          for i:=min(r,n-1) downto max(l,0) do
            if(not boolean((sq>>i)and 1))and(i*60+t[find]<(n-1)*60+59)
              then begin
                   ans[find]:=i;
                   DFS(k+1,sq or(int64(1)<<i),ren or(int64(1)<<find));
                   end;
          end;
begin
readln(n);
for i:=1 to n do
  begin
  readln(a);
  t[i]:=a mod 100+(a div 100)*60
  end;
DFS(1,0,0);
end.      

C 建房子

      把每一个可能建房屋的左上角作为处理的对象是很重要的一个想法。然后利用单调队列和前缀和可以再平方的复杂度里算出所有的代价。然后用一个双向链表维护可建造的点,暴力删除。

Codeprogram vijos1750;
uses math;
const maxn=1000;FileName='vijos1750';
type Tqueue=record
       h,t:longint;
       QA,QB:array[0..maxn]of longint;
     end;
var Q:array[1..maxn] of TQueue;
    f:array[1..maxn] of longint;
    sum:array[0..maxn,0..maxn] of int64;
    pos,height:array[0..maxn,0..maxn] of longint;
    cost:array[0..maxn*maxn]of int64;
    x,y,pre,next:array[0..maxn*maxn] of longint;
    //forbid:array[1..maxn*maxn] of boolean;
    nx,ny,i,j,n,m,a,b,tot,s:longint;
    tmp:TQueue;
function  cmp(i,j:longint):boolean;
          begin
          if cost[i]<cost[j] then exit(true);
          if cost[i]>cost[j] then exit(false);
          if x[i]<x[j] then exit(true);
          if x[i]>x[j] then exit(false);
          if y[i]<y[j] then exit(true);
          if y[i]>=y[j] then exit(false);
          end;
procedure swap(var x,y:int64);
          var t:int64;
          begin t:=x;x:=y;y:=t;end;
procedure swap(var x,y:longint);
          var t:longint;
          begin t:=x;x:=y;y:=t;end;
procedure Qsort(l,r:longint);
          var i,j,mid:longint;
          begin
          i:=l;j:=r;mid:=(l+r)>>1;
          x[0]:=x[mid];y[0]:=y[mid];cost[0]:=cost[mid];
          repeat
            while(i<r)and cmp(i,0)do inc(i);
            while(l<j)and cmp(0,j)do dec(j);
            if i<=j then begin
                    swap(cost[i],cost[j]);
                    swap(x[i],x[j]);
                    swap(y[i],y[j]);
                    inc(i);dec(j);
                    end;
          until i>j;
          if(l<j)then Qsort(l,j);
          if(i<r)then Qsort(i,r);
          end;
procedure init(var Q:TQueue);
          begin Q.h:=1;Q.t:=0;end;
function  Getmin(var Q:TQueue;x:longint):longint;
          begin
          with Q do begin
            while(h<=t)and(QA[h]>x)do inc(h);
            exit(QB[h]);end;
          end;
procedure ADD(var Q:TQueue;x,y:longint);
          begin
          with Q do begin
            while(h<=t)and(QB[t]>=y)do dec(t);
            inc(t);QA[t]:=x;QB[t]:=y;end;
          end;
function  calc(a,b,c,d:longint):int64;
          begin exit(sum[c][d]-sum[a-1][d]-
          sum[c][b-1]+sum[a-1][b-1]);end;
begin
readln(n,m,a,b);
//==getsum==
for i:=1 to n do
  for j:=1 to m do
    begin
    read(height[i][j]);
    sum[i][j]:=sum[i-1][j]+sum[i][j-1]
               -sum[i-1][j-1]+height[i][j];
    end;
//==init the Queue==
for i:=1 to n do
  begin init(Q[i]);
  for j:=m downto m-b+2 do
    ADD(Q[i],j,height[i][j]);
  end;
//==getminnum==
for j:=m-b+1 downto 1 do
  begin//处理第j列
  for i:=1 to n do begin//更新每一列最小值
    ADD(Q[i],j,height[i][j]);
    F[i]:=Getmin(Q[i],j+b-1);
    end;
  init(tmp);//初始化队列
  for i:=n downto n-a+2 do
    ADD(tmp,i,F[i]);
  for i:=n-a+1 downto 1 do//开始算
    begin inc(tot);
    ADD(tmp,i,F[i]);
    cost[tot]:=Getmin(tmp,i+a-1);
    x[tot]:=i;y[tot]:=j;end;
  end;
//===getcost===
for i:=1 to tot do
  cost[i]:=calc(x[i],y[i],x[i]+a-1,y[i]+b-1)-a*b*cost[i];
Qsort(1,tot);
for i:=1 to tot do
  begin
  pos[x[i]][y[i]]:=i;
  pre[i]:=i-1;
  next[i]:=i+1;
  end;
pre[1]:=0;next[tot]:=0;i:=1;
//==build==
while i<>0 do begin
  inc(s);pos[x[i]][y[i]]:=0;//没有这句会删掉自己
  for nx:=max(x[i]-a+1,1) to min(x[i]+a-1,n)do
    for ny:=max(y[i]-b+1,1) to min(y[i]+b-1,m)do
      if pos[nx][ny]<>0
        then begin
        j:=pos[nx][ny];
        next[pre[j]]:=next[j];
        pre[next[j]]:=pre[j];
        pos[nx][ny]:=0;end;
  i:=next[i];end;
//==output==
writeln(S);i:=1;
while i<>0 do begin
  writeln(x[i],' ',y[i],' ',cost[i]);
  i:=next[i];end;
end.      

转载于:https://www.cnblogs.com/lijianlin1995/archive/2012/10/29/2744761.html