TJOI2015题解

(转载前请标明出处,谢谢)

打算来做一波TJOI2015,来写题解啦!

Day1:

T1:[bzoj3996]

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3996

首先我们对题目中的式子化简一下,得到

121107270669345.png

于是这就成了一个最小割模型:

  • S和(i,j)连边,权值为b[i,j]
  • (i,j)和i,j分别连边,权值为inf
  • i和T连边,权值为c[i]

于是跑一下最小割就可以了;

(然而不知道发生了什么。。。最小割跑不过去。。。似乎bzoj把p党卡常数了QAQ)

(cyand神犇说他在省选的时候贪心了一发,就过了,至今找不出反例,于是我水过去了)

最小割代码如下:

  1 uses math;
  2 var s,t,n,i,j,tot,w,cnt:longint;
  3     last,pre,other,flow:array[0..2600000] of longint;
  4     l,q:array[0..3000000] of longint;
  5     ans:int64;
  6 procedure insert(a,b,c,d:longint);
  7 begin
  8   pre[tot]:=last[a];
  9   last[a]:=tot;
 10   other[tot]:=b;
 11   flow[tot]:=c;
 12   inc(tot);
 13   pre[tot]:=last[b];
 14   last[b]:=tot;
 15   other[tot]:=a;
 16   flow[tot]:=d;
 17   inc(tot);
 18 end;
 19 function bfs:boolean;
 20 var s1,t1,u,v,q1:longint;
 21 begin
 22   fillchar(q,sizeof(q),0);
 23   for i:=0 to n do
 24     l[i]:=-1;
 25   s1:=0;
 26   t1:=1;
 27   l[s]:=1;
 28   q[t1]:=s;
 29   while (s1<t1) do
 30   begin
 31     inc(s1);
 32     u:=q[s1];
 33     q1:=last[u];
 34     while (q1>=0) do
 35     begin
 36       v:=other[q1];
 37       if (flow[q1]>0) and (l[v]=-1) then
 38       begin
 39         inc(t1);
 40         q[t1]:=v;
 41         l[v]:=l[u]+1;
 42       end;
 43       q1:=pre[q1];
 44     end;
 45   end;
 46   if (l[t]=-1) then exit(false) else exit(true);
 47 end;
 48 function find(u,int:longint):longint;
 49 var w,v,q1,t1:longint;
 50 begin
 51   if (u=t) then exit(int);
 52   w:=0;
 53   q1:=last[u];
 54   while (q1>=0) and (w<int) do
 55   begin
 56     v:=other[q1];
 57     if (l[v]=l[u]+1) then
 58     begin
 59       t1:=find(v,min(flow[q1],int-w));
 60       flow[q1]:=flow[q1]-t1;
 61       flow[q1 xor 1]:=flow[q1 xor 1]+t1;
 62       w:=w+t1;
 63     end;
 64     q1:=pre[q1];
 65   end;
 66   if (w>=int) then l[u]:=-1;
 67   exit(w);
 68 end;
 69 function dinic:int64;
 70 var e:longint;
 71   ans:int64;
 72 begin
 73   ans:=0;
 74   while bfs do
 75   begin
 76     e:=find(s,maxlongint);
 77     ans:=ans+e;
 78   end;
 79   exit(ans);
 80 end;
 81 begin
 82   readln(n);
 83   s:=n*n+n+1;
 84   t:=n*n+n+2;
 85   tot:=0;
 86   for i:=0 to t do
 87     last[i]:=-1;
 88   cnt:=n;
 89   ans:=0;
 90   for i:=1 to n do
 91   begin
 92     for j:=1 to n do
 93     begin
 94       read(w);
 95       inc(cnt);
 96       insert(s,cnt,w,0);
 97       insert(cnt,i,maxlongint,0);
 98       if (i<>j) then insert(cnt,j,maxlongint,0);
 99       ans:=ans+w;
100     end;
101     readln;
102   end;
103   for i:=1 to n do
104   begin
105     read(w);
106     insert(i,t,w,0);
107   end;
108   readln;
109   n:=t;
110   writeln(ans-dinic);
111 end.
112   

贪心代码如下:

 1 var n,i,j,s,ans,max,max1:longint;
 2     b:array[0..1000,0..1000] of longint;
 3     c,inc:array[0..1000] of longint;
 4 begin
 5   readln(n);
 6   for i:=1 to n do
 7   begin
 8     for j:=1 to n do
 9         read(b[i,j]);
10     readln;
11   end;
12   for i:=1 to n do
13     read(c[i]);
14   readln;
15   fillchar(inc,sizeof(inc),0);
16   s:=0;
17   ans:=0;
18   for i:=1 to n do
19   begin
20     s:=0;
21     for j:=1 to n do
22         s:=s+b[i,j]+b[j,i];
23     inc[i]:=b[i,i]-s+c[i];
24   end;
25   for i:=1 to n do
26     for j:=1 to n do
27         ans:=ans+b[i,j];
28   for i:=1 to n do
29     ans:=ans-c[i];
30   while true do
31   begin
32     max:=-1;
33     max1:=-1;
34     for i:=1 to n do
35       if (max<inc[i]) then
36       begin
37         max:=inc[i];
38         max1:=i;
39       end;
40     if (max1=-1) then break;
41     ans:=ans+max;
42     for i:=1 to n do
43       inc[i]:=inc[i]+b[i,max1]+b[max1,i];
44     inc[max1]:=-1;
45   end;
46   writeln(ans);
47 end.
48     

T2:[bzoj3997]

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3997

本题要用一个Dilworth定理:DAG最小链覆盖=最大独立子集,

于是发现最大独立子集显然符合题目,于是直接跑DP就可以了,方程如下:

f[i,j]=max{f[i-1,j+1]+a[i,j],f[i-1,j],f[i,j+1]}

代码如下:

 1 var t,l,n,m,i,j:longint;
 2     a,f:array[0..1005,0..1005] of int64;
 3 begin
 4   readln(t);
 5   for l:=1 to t do
 6   begin
 7     readln(n,m);
 8     fillchar(a,sizeof(a),0);
 9     fillchar(f,sizeof(f),0);
10     for i:=1 to n do
11     begin
12       for j:=1 to m do
13         read(a[i,j]);
14       readln;
15     end;
16     for i:=1 to n do
17         for j:=m downto 1 do
18         begin
19           f[i,j]:=f[i-1,j+1]+a[i,j];
20           if (f[i-1,j]>f[i,j]) then f[i,j]:=f[i-1,j];
21           if (f[i,j+1]>f[i,j]) then f[i,j]:=f[i,j+1];
22         end;
23     writeln(f[n,1]);
24   end;
25 end.

 T3:[bzoj3998]

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3998

这题把我快写哭了QAQQQ。。。

这题是一个裸的后缀自动机,(然而我并不会,于是去看hzwer的博客)

于是写啊写啊写。。。然后狂WA不止。。。

问题在于,pascal党这里自动机建完以后千万不能写递归DFS。。。(C++党随意)

pascal党可以改成非递归形式或者拓扑排序,就可以了QAQQQ。。。

终于AC了,撒花撒花!!!

代码如下:

  1 var ch:array[0..500005] of char;
  2     x:char;
  3     n,i,j,tt,k,last,cnt,tot:longint;
  4     a:array[0..1000005,0..25] of longint;
  5     fa,mx,val,v,q,sum:array[0..1000005] of int64;
  6 procedure extend(c:longint);
  7 var p,np,q,nq,i,j:longint;
  8 begin
  9   p:=last;
 10   inc(cnt);
 11   last:=cnt;
 12   np:=last;
 13   mx[np]:=mx[p]+1;
 14   val[np]:=1;
 15   while (a[p,c]=0) and (p<>0) do
 16   begin
 17     a[p,c]:=np;
 18     p:=fa[p];
 19   end;
 20   if (p=0) then fa[np]:=1
 21   else
 22   begin
 23     q:=a[p,c];
 24     if (mx[p]+1=mx[q]) then fa[np]:=q
 25     else
 26     begin
 27       inc(cnt);
 28       nq:=cnt;
 29       mx[nq]:=mx[p]+1;
 30       a[nq]:=a[q];
 31       fa[nq]:=fa[q];
 32       fa[q]:=nq;
 33       fa[np]:=fa[q];
 34       while (a[p,c]=q) do
 35       begin
 36         a[p,c]:=nq;
 37         p:=fa[p];
 38       end;
 39     end;
 40   end;
 41 end;
 42 procedure pre;
 43 var i,j:longint;
 44     t:int64;
 45 begin
 46   for i:=1 to cnt do
 47     inc(v[mx[i]]);
 48   for i:=1 to n do
 49     v[i]:=v[i]+v[i-1];
 50   for i:=cnt downto 1 do
 51   begin
 52     q[v[mx[i]]]:=i;
 53     dec(v[mx[i]]);
 54   end;
 55   for i:=cnt downto 1 do
 56   begin
 57     t:=q[i];
 58     if (tt=1) then val[fa[t]]:=val[fa[t]]+val[t] else val[t]:=1;
 59   end;
 60   val[1]:=0;
 61   for i:=cnt downto 1 do
 62   begin
 63     t:=q[i];
 64     sum[t]:=val[t];
 65     for j:=0 to 25 do
 66       sum[t]:=sum[t]+sum[a[t,j]];
 67   end;
 68 end;
 69 procedure dfs(x:longint);
 70 var i:longint;
 71     flag:boolean;
 72 begin
 73   while (k>val[x]) do
 74   begin
 75     k:=k-val[x];
 76     flag:=false;
 77     for i:=0 to 25 do
 78     begin
 79     if (a[x,i]>0) and not(flag) then
 80     begin
 81       if (k<=sum[a[x,i]]) then
 82       begin
 83         write(chr(i+97));
 84         x:=a[x,i];
 85         flag:=true;
 86       end
 87           else
 88       k:=k-sum[a[x,i]];
 89     end;
 90     end;
 91   end;
 92 end;
 93 begin
 94   n:=0;
 95   read(x);
 96   while not((ord(x)>=48) and (ord(x)<=57)) do
 97   begin
 98     if (ord(x)>=97) and (ord(x)<=97+25) then
 99     begin
100       inc(n);
101       ch[n]:=x;
102     end;
103     read(x);
104   end;
105   while not((ord(x)>=48) and (ord(x)<=57)) do read(x);
106   tt:=ord(x)-48;
107   read(x);
108   readln(k);
109   last:=1;
110   cnt:=1;
111   fillchar(fa,sizeof(fa),0);
112   fillchar(mx,sizeof(mx),0);
113   fillchar(val,sizeof(val),0);
114   fillchar(sum,sizeof(sum),0);
115   fillchar(v,sizeof(v),0);
116   fillchar(q,sizeof(q),0);
117   for i:=1 to n do
118     extend(ord(ch[i])-97);
119   pre;
120   tot:=0;
121   if (k>sum[1]) then write('-1') else dfs(1);
122   writeln;
123 end.

Day2:

(T1留个坑,之后补)

T2:[bzoj4000]

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4000

这一题真心有毒QAQQQ

首先题目意思理解继续要读10遍题目QAQQQ注意行数是从0开始的QAQQQ

然后就是一个状态压缩DP。。。

显然过不了TATTT。。。

那就来一发矩阵乘法!

这就是正解了。。。然后作为pascal党的我木有过。。。这题bzoj上面pascal要用double(卡精度)。。。于是TLE。。。

不过介于cojs上面过了,所以一样贴过来了。

代码如下:

  1 type arr=array[0..70,0..70] of int64;
  2 var n,m,p,k,i,j,x,max:longint;
  3     a:arr;
  4     f:array[0..70] of longint;
  5     mp:array[0..2,0..100] of longint;
  6     ans,modp:int64;
  7 function time(a:arr;b:longint):arr;
  8 var ans,now,anss:arr;
  9     i,j,k,r:longint;
 10 begin
 11   fillchar(ans,sizeof(ans),0);
 12   for i:=0 to max do
 13     ans[i,i]:=1;
 14   now:=a;
 15   r:=b;
 16   while (r>0) do
 17   begin
 18     if (r mod 2=1) then
 19     begin
 20       fillchar(anss,sizeof(anss),0);
 21       for i:=0 to max do
 22         for j:=0 to max do
 23             for k:=0 to max do
 24                 anss[i,j]:=(anss[i,j]+(int64(ans[i,k]*now[k,j])));
 25       ans:=anss;
 26     end;
 27     r:=r div 2;
 28     fillchar(anss,sizeof(anss),0);
 29     for i:=0 to max do
 30       for j:=0 to max do
 31         for k:=0 to max do
 32             anss[i,j]:=anss[i,j]+(int64(now[i,k]*now[k,j]));
 33     now:=anss;
 34   end;
 35   exit(ans);
 36 end;
 37 function tryit(a,b:longint):boolean;
 38 var i,j,t,k:longint;
 39 begin
 40     for i:=0 to m-1 do
 41     begin
 42       if ((a shr i) and 1<>0) then
 43       begin
 44         for j:=1 to mp[1,0] do
 45         begin
 46           k:=i+mp[1,j];
 47           if (k>=0) and (k<=m-1) and ((a shl k) and 1<>0) then exit(false);
 48         end;
 49         for j:=1 to mp[2,0] do
 50         begin
 51           k:=i+mp[2,j];
 52           if (k>=0) and (k<=m-1) and ((b shr k) and 1<>0) then exit(false);
 53         end;
 54       end;
 55     end;
 56     for i:=0 to m-1 do
 57     begin
 58       if ((b shr i) and 1<>0) then
 59       begin
 60         for j:=1 to mp[1,0] do
 61         begin
 62           k:=i+mp[1,j];
 63           if (k>=0) and (k<=m-1) and ((b shr k) and 1<>0) then exit(false);
 64         end;
 65         for j:=1 to mp[0,0] do
 66         begin
 67           k:=i+mp[0,j];
 68           if (k>=0) and (k<=m-1) and ((a shr k) and 1<>0) then exit(false);
 69         end;
 70       end;
 71     end;
 72     exit(true);
 73 end;
 74 begin
 75   modp:=1;
 76   for i:=1 to 32 do
 77     modp:=int64(modp*2);
 78   readln(n,m);
 79   readln(p,k);
 80   max:=1 shl m;
 81   dec(max);
 82   fillchar(mp,sizeof(mp),0);
 83   for i:=0 to 2 do
 84   begin
 85     for j:=0 to p-1 do
 86     begin
 87       read(x);
 88       if (x=1) and not((i=1) and (j=k)) then
 89       begin
 90         inc(mp[i,0]);
 91         mp[i,mp[i,0]]:=j-k;
 92       end;
 93     end;
 94   end;
 95   fillchar(a,sizeof(a),0);
 96   fillchar(f,sizeof(f),0);
 97   for i:=0 to max do
 98     for j:=0 to max do
 99         if tryit(i,j) then a[i,j]:=1 else a[i,j]:=0;
100   for i:=0 to max do
101     f[i]:=a[0,i];
102   a:=time(a,n);
103   ans:=0;
104   for i:=0 to max do
105   begin
106     if (f[i]<>0) then ans:=(ans+a[i,0]) mod modp;
107     while (ans>=modp) do ans:=ans-modp;
108     while (ans<0) do ans:=ans+modp;
109   end;
110   writeln(ans);
111 end.
112     

 T3:[bzoj4001]

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4001

这一题一定是这次省选最友善的一个题。。。

首先我们可以打暴力(或者手算),于是找到了规律,

可以用组合数学证明一发(然而我不会。。。)QAQQQ

总之就是个结论题QAQQQ

代码如下:

1 var n:longint;
2     x:real;
3 begin
4   readln(n);
5   x:=n/(2*n-1);
6   x:=x*(n+1)/2;
7   writeln(x:0:9);
8 end.
原文地址:https://www.cnblogs.com/Tommyr7/p/5874806.html