由於題目不是自己人出的,所以題面就不給了吧
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 枚舉+驗證