P2197 [JZOJ/中山市市选] 三核苷酸

考虑 \(\sum (N_i-mval)^2=\sum {N_i}^2-2\times N_i \times mval+mval^2\),我们用一个 \(tot\) 记录贡献个数,用 \(val\) 记录贡献和,\(ans\) 为每一个贡献的方的和。

由于答案是每一个两两的贡献,我们再定义 \(queue_{a,b,c,t}\) 代表 \(a,b,c\) 这种块的第 \(t\) 个出现的位置存一下。\(match_{a,b,c,t}\) 代表 \(queue_{a,b,c,t}-queue_{a,b,c,t-1}\)。用 \(tail_{a,b,c}\) 代表 \(queue\) 的指针。

首先 \(queue_{a,b,c,t}\)\(match_{a,b,c,t}\) 的转移十分的显然。

但是仅仅这样是不够的,我们设 \(sum_{a,b,c}\) 代表这种块的贡献的后缀和的和。设 \(square_{a,b,c}\) 代表这种块的贡献的后缀和后的每一个数的平方的和

比如:

\(tail_{a,b,c}=\) 3

\(queue_{a,b,c}=\) i | j | k

\(match_{a,b,c}=\) x | y 或者说 j-i | k-j

\(sum_{a,b,c}=\) x+2*y (x+y | y)

\(square_{a,b,c}=\) (x+y)^2+y^2

现在我们来看一下答案的更新。(我们用 \(X\) 代表 \(tail_{a,b,c}-1\),\(tmp\) 代表 \(match_{a,b,c}\))

\[tot+=X \]

\[val+=sum_{a,b,c} \]

\[ans+=square_{a,b,c}+2 \times tmp*sum_{a,b,c}+X*tmp^2 \]

更新的时候也很简单

\[square_{a,b,c}+=tmp^2*X+2 \times tmp*sum_{a,b,c} \]

\[sum+=tmp*X \]

神奇 \(60\) 分,公式没有问题...

Const
	total=100010;

var
	match,queue:array[1..4,1..4,1..4,-1..total] of longint;
	sum,tail,square:array[1..4,1..4,1..4] of longint;
	num:array[-1..total] of longint;
	i,j,k,n,m,a,b,c,tmp,test:longint;
	val,tot,ans:int64;
	exist:boolean;
	s:ansistring;

// match 表示上一个与此相同的字符串的位置差,queue 表示与此字符串相同的位置集合
// sum 表示 match 的后缀和的和,square 为 match 的后缀和的平方和
// tot 为个数,val 是和,ans 为平方和

procedure Work;
var len:longint;
begin
	fillchar(square,sizeof(square),0);
	fillchar(queue,sizeof(queue),0);
	fillchar(match,sizeof(match),0);
	fillchar(tail,sizeof(tail),0);
	fillchar(sum,sizeof(sum),0);
	fillchar(num,sizeof(num),0);
	readln(s); len:=length(s);
	ans:=0; tot:=0; val:=0; exist:=True;
	for i:=1 to len do
		Case s[i] of
			'A' : num[i]:=1; 'G' : num[i]:=2; 'C' : num[i]:=3; 'T' : num[i]:=4;
		end;
	for i:=1 to len-2 do
	begin
		a:=num[i]; b:=num[i+1]; c:=num[i+2];
		inc(tail[a,b,c]); queue[a,b,c,tail[a,b,c]]:=i;
        if tail[a,b,c]=1 then continue;
		match[a,b,c,tail[a,b,c]]:=i-queue[a,b,c,tail[a,b,c]-1]+1;
        tmp:=match[a,b,c,tail[a,b,c]]; dec(tail[a,b,c]);
		inc(ans,square[a,b,c]+tmp*(sum[a,b,c] << 1)+tail[a,b,c]*sqr(tmp)); 
		inc(square[a,b,c],sqr(tmp)*tail[a,b,c]+tmp*(sum[a,b,c] << 1));
		inc(sum[a,b,c],tmp*tail[a,b,c]);
		inc(val,sum[a,b,c]); inc(tot,tail[a,b,c]); inc(tail[a,b,c]);
	end;
	for i:=1 to 4 do for j:=1 to 4 do for k:=1 to 4 do if tail[i,j,k]>1 then exist:=False;
	if exist then begin writeln('0.000000'); exit; end; writeln(ans,' ',val,' ',tot);
	writeln(ans/tot-sqr(val/tot):0:6);
end;

begin
	{assign(input,'tri.in');reset(input);
	assign(output,'tri.out');rewrite(output);}
   	readln(test);
	while test>0 do begin Work; dec(test); end;
	close(input); close(output);
end.
posted @ 2019-04-13 15:05  _ARFA  阅读(174)  评论(0编辑  收藏  举报