最近的幾道好題

來源:互聯網
上載者:User

由於題目不是自己人出的,所以題面就不給了吧

CSDN貼代碼不能縮到一起了,所以這篇文章會顯得比較冗長

Day1:

1.Hash or 尾碼數組

大概的做法:枚舉答案長度,暴力匹配驗證答案即可

代碼:

program syj;type  arr=array[0..200005]of longint;var  m,task,n,i,j,k,l,z,ans,o:longint;  aa,a,b,c,sa,tmp,rank:arr;  h:array[0..19]of arr;  cc:char;  tm:real;procedure sort(var a:arr);begin  fillchar(c,sizeof(c),0);  for i:=1 to n do inc(c[a[i]+1]);  for i:=1 to o do inc(c[i],c[i-1]);  for i:=1 to n do begin    inc(c[a[sa[i]]]);    tmp[c[a[sa[i]]]]:=sa[i];  end;  for i:=1 to n do sa[i]:=tmp[i];end;procedure getrank;begin  o:=0;  for i:=1 to n do begin    inc(o,ord((a[sa[i]]<>a[sa[i-1]])or(b[sa[i]]<>b[sa[i-1]])));    rank[sa[i]]:=o;  end;end;function ask(i,j:longint):longint;begin  if i=j then exit(n-i+1);  i:=rank[i];j:=rank[j];  if i>j then begin    z:=i;i:=j;j:=z;  end;  inc(i);  k:=trunc(ln(j-i+1)/ln(2)+1e-8);  if h[k,i]<h[k,j-1<<k+1] then ask:=h[k,i]  else ask:=h[k,j-1<<k+1];end;function check1(i:longint):boolean;var j,k,l:longint;begin  j:=ask(1,i);  k:=i+j;  if k<=i then exit(false);  l:=ask(k+1,j+1);  if j+l>k-1 then l:=k-1-j;  if k+l=n then exit(true);  if j+l<i-1 then exit(false);  if j+l+1<k then exit(false);  exit(k+l+ask(k+1,k+l+1)=n);end;function check2(i:longint):boolean;var j:longint;begin  j:=ask(1,i);  if (j=0)or(j+1>=i) then exit(false);  exit(i+j+ask(j+2,i+j)-1=n);end;procedure debug;var i,j:longint;begin  for i:=1 to n do begin    for j:=1 to n do      write(ask(i,j),' ');    writeln;  end;end;function check3(i:longint):boolean;begin  check3:=(i>2)and(ask(i,2)=n-i+1);end;begin  assign(input,'naj.in');reset(input);  assign(output,'naj.out');rewrite(output);  readln(task);  for task:=1 to task do begin    read(n,cc);    fillchar(a,sizeof(a),0);    fillchar(b,sizeof(b),0);    fillchar(rank,sizeof(rank),0);    fillchar(sa,sizeof(sa),0);    fillchar(aa,sizeof(aa),0);    fillchar(h,sizeof(h),0);    for i:=1 to n do begin      read(cc);      a[i]:=ord(cc)-96;      aa[i]:=a[i];      b[i]:=0;    end;    readln;    for i:=1 to n do sa[i]:=i;    o:=26;    sort(a);getrank;    l:=1;    while o<>n do begin      for i:=1 to n do begin        a[i]:=rank[i];        if i+l<=n then b[i]:=rank[i+l]        else b[i]:=0;      end;      sort(b);sort(a);getrank;      l:=l*2;    end;    l:=0;    for i:=1 to n do begin      if l>0 then dec(l);      if rank[i]=1 then continue;      j:=sa[rank[i]-1];      while (i+l<=n)and(j+l<=n)and(aa[i+l]=aa[j+l]) do inc(l);      h[0,rank[i]]:=l;    end;    m:=trunc(ln(n)/ln(2)+1e-8);    for j:=1 to m do      for i:=1 to n-1<<j+1 do        if h[j-1,i]<h[j-1,i+1<<(j-1)] then          h[j,i]:=h[j-1,i]        else          h[j,i]:=h[j-1,i+1<<(j-1)];    ans:=n-1;    for i:=2 to n do      if check2(i)or check3(i) then begin        ans:=i-2;break;      end else      if check1(i) then begin        ans:=i-1;break;      end;    writeln(ans);  end;  close(input);close(output);end.

2.複合方法(按答案與sqrt(n)的大小分情況討論)、分塊、排序+樹狀數組

答案 > sqrt(n)時是很好辦的,分塊+二分尋找即可

而答案 < sqrt(n)時相對麻煩一點,由於空間的問題,不能直接開sqrt(n)*n的預先處理數組,我們就從1~sqrt(n)枚舉答案,得到O(n)個區間後再用排序+樹狀數組更新一遍所有詢問的答案

ps:我寫的程式速度極慢無比,極限資料得跑40s。囧。還有一點,pascal的類還挺好用的。

代碼:

program syj;uses  math,sysutils;type  lisanhua=object    a:array[0..500001]of longint;    t:longint;    procedure put(i:longint);    procedure sort(l,r:longint);    function get(i:longint):longint;  end;var  s,n,m,i,j,k,t,z,q:longint;  a,b,l,r,p,lmi,lma,rmi,rma,lc,rc:array[0..50001]of longint;  u,v,w:array[0..500001]of longint;  ans,x,y:array[0..200001]of longint;  f:array[0..500001]of boolean;  o:lisanhua;  tm:real;procedure lisanhua.put(i:longint);begin  inc(t);a[t]:=i;end;procedure lisanhua.sort(l,r:longint);var i,j:longint;begin  i:=l;j:=r;a[0]:=a[(l+r)>>1];  repeat    while a[i]<a[0] do inc(i);    while a[j]>a[0] do dec(j);    if i<=j then begin      z:=a[i];a[i]:=a[j];a[j]:=z;      inc(i);dec(j);    end;  until i>j;  if l<j then sort(l,j);  if i<r then sort(i,r);end;function lisanhua.get(i:longint):longint;var l,r,m:longint;begin  l:=1;r:=t;  while l<r do begin    m:=(l+r)>>1;    if i<=a[m] then r:=m    else l:=m+1;  end;end;procedure up(i,k:longint);begin  if k>ans[i] then ans[i]:=k;end;function ok(l1,r1,l2,r2:longint):boolean;begin  ok:=not((l1>r2)or(l2>r1));end;function findl(i,k:longint):longint;var l,r,m:longint;begin  if i=0 then exit(0);  l:=lc[i];r:=rc[i];  while l<r do begin    m:=(l+r)>>1;    if ok(x[k],y[k],rma[m],rmi[m]) then r:=m    else l:=m+1;  end;  if not ok(x[k],y[k],rma[l],rmi[l]) then inc(l);  findl:=rc[i]-l+1;end;function findr(i,k:longint):longint;var l,r,m:longint;begin  if i>t then exit(0);  l:=lc[i];r:=rc[i];  while l<r do begin    m:=(l+r+1)>>1;    if ok(x[k],y[k],lma[m],lmi[m]) then l:=m    else r:=m-1;  end;  if not ok(x[k],y[k],lma[l],lmi[l]) then dec(l);  findr:=l-lc[i]+1;end;procedure add(x,y,z:longint);begin  inc(q); u[q]:=x;v[q]:=y;w[q]:=z;end;procedure sort(l,r:longint);var i,j:longint;begin  i:=l;j:=r;u[0]:=u[(l+r)>>1];w[0]:=w[(l+r)>>1];  repeat    while (u[i]<u[0])or(u[i]=u[0])and(w[i]<w[0]) do inc(i);    while (u[j]>u[0])or(u[j]=u[0])and(w[j]>w[0]) do dec(j);    if i<=j then begin      z:=u[i];u[i]:=u[j];u[j]:=z;      z:=v[i];v[i]:=v[j];v[j]:=z;      z:=w[i];w[i]:=w[j];w[j]:=z;      inc(i);dec(j);    end;  until i>j;  if l<j then sort(l,j);  if i<r then sort(i,r);end;procedure update(i:longint);begin  while i>0 do begin    f[i]:=true;    i:=i-i and-i;  end;end;function ask(i:longint):longint;begin  while i<=o.t do begin    if f[i] then exit(1);    i:=i+i and-i;  end;  ask:=0;end;procedure work(len:longint);var i:longint;begin  q:=0;  for i:=1 to n-len+1 do add(l[i],r[i],0);  for i:=1 to m do if len>ans[i] then add(y[i],x[i],i);  sort(1,q);  fillchar(f,sizeof(f),0);  for i:=1 to q do    if w[i]=0 then update(v[i])    else up(w[i],ask(v[i])*len);end;begin  tm:=time;  assign(input,'kan.in');reset(input);  assign(output,'kan.out');rewrite(output);  readln(n,m);  o.t:=0;  for i:=1 to n do begin    readln(a[i],b[i]);    o.put(a[i]);o.put(b[i]);  end;  for i:=1 to m do begin    readln(x[i],y[i]);    o.put(x[i]);    o.put(y[i]);  end;  o.sort(1,o.t);  for i:=1 to n do begin    a[i]:=o.get(a[i]);    b[i]:=o.get(b[i]);  end;  for i:=1 to m do begin    x[i]:=o.get(x[i]);    y[i]:=o.get(y[i]);  end; // writeln('lisanhua : ',(time-tm)*24*3600:0:2);  tm:=time;  s:=min(n,max(trunc(sqrt(n)),3));  j:=1;t:=1;  for i:=1 to n do begin    p[i]:=t;    if j=s then begin      j:=1;inc(t)    end else inc(j);  end;  if j=1 then dec(t);  for i:=1 to n do    if p[i]<>p[i-1] then begin      lc[p[i]]:=i;      lma[i]:=a[i];      lmi[i]:=b[i];    end else begin      lma[i]:=max(a[i],lma[i-1]);      lmi[i]:=min(b[i],lmi[i-1]);    end;  for i:=n downto 1 do    if p[i]<>p[i+1] then begin      rc[p[i]]:=i;      rma[i]:=a[i];      rmi[i]:=b[i];    end else begin      rma[i]:=max(a[i],rma[i+1]);      rmi[i]:=min(b[i],rmi[i+1]);    end;  lc[t+1]:=n+1;rc[t+1]:=n+1;  lma[n+1]:=o.t+1;lmi[n+1]:=o.t+1;  for i:=1 to m do begin    k:=1;    for j:=1 to t+1 do      if not ok(x[i],y[i],lma[rc[j]],lmi[rc[j]]) then begin        z:=findl(k-1,i)+rc[j-1]-lc[k]+1+findr(j,i);        up(i,z);        k:=j+1;      end;  end; // writeln('>sqrt(n) : ',(time-tm)*24*3600:0:2);  tm:=time;  l:=a;r:=b;  work(1);  for i:=1 to s-1 do begin    for j:=1 to n-i do begin      l[j]:=max(l[j],a[i+j]);      r[j]:=min(r[j],b[i+j]);    end;    work(i+1);  end; // writeln('<sqrt(n) : ',(time-tm)*24*3600:0:2);  for i:=1 to m do    writeln(ans[i]);  close(input);close(output);end.

3.插頭DP or 費用流 or 最大流

插頭DP的方法,討論的時候好像是DYF講了

費用流的方法題解裡有

實際上這道題是可以直接用最大流求解的,出題人竟然沒想到?!

思想跟費用流的方法是一樣的,基於度數分配

用(i, j, L, R)表示i向j連一條下界為L,上界為R的邊,s表示源,t表示匯

具體方法:

先黑白染色

(s, 黑點, 在邊界上為1不在邊界上為2, 2) (*)

(黑點, 相鄰的白點, 0, 1)

(白點, t, 在邊界上為1不在邊界上為2, 2) (*)

求最大流

最後答案就是(*)邊中只流了1的流量的邊數除以2

代碼:

program syj;const  fx:array[1..4]of longint=(-1,0,1,0);  fy:array[1..4]of longint=(0,1,0,-1);var  flow,n,m,i,j,k,x,y,ans,s,t,ss,tt,kk,e:longint;  q,d,pre,fir,h:array[0..300]of longint;  next,point,w:array[0..2000]of longint;  o:array[0..2000]of boolean;  a:array[0..15,0..15]of longint;  cc:char;function bfs:boolean;var i,j,k,st,ed:longint;begin  fillchar(d,sizeof(d),$FF);  st:=0;ed:=1;q[1]:=ss;d[ss]:=0;  while st<ed do begin    inc(st);i:=q[st];j:=h[i];    while j<>0 do begin      k:=point[j];      if (w[j]>0)and(d[k]=-1) then begin        d[k]:=d[i]+1;inc(ed);q[ed]:=k;        if k=tt then exit(true);      end;      j:=next[j];    end;  end;  bfs:=false;end;function ff(i:longint):string;begin  if i=s then ff:='s' else  if i=t then ff:='t' else  if i=ss then ff:='ss' else  if i=tt then ff:='tt' else str(i,ff);end;procedure imp;var i,j:longint;begin  i:=pre[tt];j:=maxlongint;//  write(ff(tt),' ');  while i<>0 do begin//    write(ff(i),' ');    if w[fir[i]]<=j then begin j:=w[fir[i]];kk:=i end;    i:=pre[i];  end;//  writeln(': ',j);  i:=pre[tt];  while i<>0 do begin    dec(w[fir[i]],j);    inc(w[fir[i]xor 1],j);    i:=pre[i];  end;  dec(flow,j);end;procedure dfs;var i,j,k:longint;ok:boolean;begin  for i:=1 to tt do fir[i]:=h[i];  i:=ss;pre[ss]:=0;  while i<>0 do begin    j:=fir[i];ok:=true;    while j<>0 do begin      k:=point[j];      if (w[j]>0)and(d[k]=d[i]+1) then begin        pre[k]:=i;fir[i]:=j;ok:=false;i:=k;        if k=tt then begin imp;i:=kk end;        break;      end;      j:=next[j];    end;    if ok then begin      d[i]:=-1;i:=pre[i];    end;  end;end;procedure link(x,y,z:longint;oo:boolean);begin  if z=0 then exit;  inc(e); next[e]:=h[x];point[e]:=y;w[e]:=z;o[e]:=oo;h[x]:=e;  inc(e); next[e]:=h[y];point[e]:=x;w[e]:=0;h[y]:=e;end;procedure add(i,j,k,l:longint);begin  link(ss,j,k,false);  link(i,tt,k,false);  link(i,j,l-k,k=1);  inc(flow,k);end;begin  assign(input,'snake.in');reset(input);  assign(output,'snake.out');rewrite(output);  while not seekeof do begin    inc(n);    m:=0;    while not seekeoln do begin      inc(m);      read(cc);      if cc='.' then begin        inc(tt);        a[n,m]:=tt;      end;    end;    readln;  end;  s:=tt+1;t:=s+1;ss:=t+1;tt:=ss+1;e:=1;  for i:=1 to n do    for j:=1 to m do if a[i,j]>0 then      if odd(i+j) then begin        add(s,a[i,j],2-ord((i=1)or(j=1)or(i=n)or(j=m)),2);        for k:=1 to 4 do begin          x:=i+fx[k];y:=j+fy[k];          if a[x,y]>0 then link(a[i,j],a[x,y],1,false);        end;      end else        add(a[i,j],t,2-ord((i=1)or(j=1)or(i=n)or(j=m)),2);  link(t,s,maxlongint,false);  while bfs do dfs;  if flow>0 then begin    writeln(-1);    close(input);close(output);    halt;  end;  ss:=s;tt:=t;  w[e]:=0;w[e-1]:=0;  while bfs do dfs;  for i:=2 to e do    if o[i]and(w[i]=1) then      inc(ans);  writeln(ans>>1);  close(input);close(output);end.

Day2

1.離散化、匹配

通過很麻煩的預先處理之後就是一個裸的最優匹配問題了

直接KM可以過,也可以排序後匈牙利

我這道題的代碼過於醜陋就不貼了吧

2.枚舉、凸包

枚舉一條分界線,左邊求個凸包右邊求個凸包,更新答案即可

需要注意一下多點共線的情況

3.數論

可以發現ans = (x - 1) ^ n,然後問題就轉化成求形如a ^ b mod c = d的所有的a

具體求法見下一篇文章

代碼:

program syj;uses  math;const  mo=1<<18-1;type  Thash=object    t:longint;    ne,b:array[0..100000]of longint;    a:array[0..100000]of int64;    h:array[0..mo+1]of longint;    procedure hash(x:int64;y:longint);    function find(x:int64):longint;    procedure clear;    procedure sort;  end;var  b,c,d,p,q,x,y:int64;  e:array[0..20]of int64;  i,j:longint;  o:Thash;procedure Thash.hash(x:int64;y:longint);var i,j:longint;begin  i:=x and mo;j:=h[i];  while j<>0 do begin    if a[j]=x then exit;    j:=ne[j];  end;  inc(t); ne[t]:=h[i];a[t]:=x;b[t]:=y;h[i]:=t;end;function Thash.find(x:int64):longint;var i,j:longint;begin   i:=x and mo;j:=h[i];   while j<>0 do begin     if a[j]=x then exit(b[j]);     j:=ne[j];   end;   exit(-1);end;procedure Thash.clear;begin  t:=0;  fillchar(h,sizeof(h),0);end;procedure Thash.sort;var i,j,z:longint;begin  for i:=1 to t-1 do    for j:=i+1 to t do      if a[i]>a[j] then begin        z:=a[i];a[i]:=a[j];a[j]:=z;      end;end;function prime(i:int64):boolean;var j:longint;begin  if (i=1)or not odd(i) then exit(false);  for j:=2 to trunc(sqrt(i)) do    if i mod j=0 then      exit(false);  prime:=true;end;function mul(a,b:int64):int64;begin  if b=0 then mul:=1 else begin    mul:=mul(a,b>>1);    mul:=mul*mul mod c;    if odd(b) then      mul:=mul*a mod c;  end;end;function root(n:int64):int64;var ok:boolean;begin  if n=2 then root:=1;  for i:=2 to n do begin    ok:=true;    for j:=1 to e[0] do      if mul(i,(c-1)div e[j])=1 then begin        ok:=false;break;      end;    if ok then exit(i);  end;end;procedure devide(c:int64);begin  for i:=2 to trunc(sqrt(c)) do    if c mod i=0 then begin      inc(e[0]);e[e[0]]:=i;      while c mod i=0 do c:=c div i;    end;  if c>1 then begin    inc(e[0]);e[e[0]]:=c;  end;end;function giant(a,c,d:int64):int64;var z,s:int64; j,k:longint;begin  z:=1; k:=ceil(sqrt(c));  for i:=0 to k-1 do begin    o.hash(z,i);    z:=z*a mod c;  end;  s:=1;  for i:=0 to k-1 do begin    j:=o.find(mul(s,c-2)*d mod c);    if j<>-1 then exit(i*k+j);    s:=s*z mod c;  end;  giant:=-1;end;function exgcd(a,b:int64;var x,y:int64):int64;begin  if b=0 then begin    x:=1;y:=0;    exgcd:=a;  end else begin    exgcd:=exgcd(b,a mod b,y,x);    y:=y-a div b*x;  end;end;procedure solve(a,b,c:int64);var u,v:int64;begin  d:=exgcd(a,b,u,v);  if c mod d<>0 then exit;  b:=b div d;  u:=c div d*u;  x:=(u mod b+b)mod b;  y:=b;  if x=0 then inc(x,b);end;begin  assign(input,'wa.in');reset(input);  assign(output,'wa.out');rewrite(output);  readln(b,d,c);  if not prime(c) then c:=2;  devide(c-1);  p:=root(c);  q:=giant(p,c,d);  solve(b,c-1,q);  o.clear;  for i:=0 to d-1 do begin    j:=mul(p,x);    o.hash(mul(j,b-1)*(j+1)mod c,j);    inc(x,y);  end;  o.sort;  writeln(o.t);  for i:=1 to o.t do write(o.a[i],' ');  close(input);close(output);end.

Day3

1.容斥原理 or 打表找規律

d(n) = n mod 9,然後枚舉d(n),解同餘方程 + 容斥原理 or 打表找規律即可

2.二分答案+上下界網路流

感覺上這道題跟THSC的第二題差不多

先二分答案

由於∑a是常數,所以將絕對值符號拆掉後,就是一個分配流量的上下界網路流模型,判斷是否有解即可

3.最短路

POI原題

求log(n)次最短路的方法加一點常數最佳化是可以過的

實際上可以只求一次最短路。

在求最短路的同時順便求一個次短路,記錄最短路是由哪條源點直接連出去的邊更新過來的,然後枚舉從那條邊回到源點更新答案時分情況討論一下即可

Day4

1.構造

首先可以發現排完序後的所有串的最後一位構成的新序列的字母組成是和原串一樣的

然後可以發現排完序後的所有串的最後一位在原串中的後一個就是排完序後的所有串的第一位

而第i個“第一位”實際上就是原串的字典序第i大的尾碼對應的字母

然後掃一遍即可得到答案

需要注意的是原串可能有迴圈節,此時最後跑出來的會是幾個獨立的環

2.貪心+堆

可以發現當前權值最大的點一定會在它的父親選完後馬上選,那麼就可以將這個點和他父親合并

列一列式子之後發現這個新點的權值等價於這一塊點的權值的算術平均數

用個堆每次拿一個權值最大的點即可

3.上下界網路流

裸題

Day5

1.圖論

2.矩陣DP

3.(提交答案題)手玩 or 調整 or 枚舉+驗證

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.