[Jzoj] 2197. 三核苷酸

题目描述

三核苷酸是组成 D N A DNA 序列的基本片段。具体来说,核苷酸一共有 4 4 种,分别用 A G C T ’A’,’G’,’C’,’T’ 来表示。而三核苷酸就是由 3 3 个核苷酸排列而成的 D N A DNA 片段

三核苷酸一共有 64 64 种。给定一个长度为 L L D N A DNA 序列,一共可以分辨出 L 2 (L-2) 个三核苷酸。现在我们想用一些统计学的方法来进行一些分析,步骤如下:

1. 1. 对于这 L 2 (L-2) 个三核苷酸,我们从左到右给予编号,分别为 1 1 L 2 L-2

2. 2. 从这 L 2 (L-2) 个三核苷酸挑选一对出来,一共有 ( L 2 ) ( L 3 ) / 2 (L-2)*(L-3)/2 种可能。如果某一对三核苷酸是一样的,我们就记录他们之间的距离。他们之间的距离定义为他们的编号之差。

3. 3. 根据我们所记录的“样本数据”,我们现在需要计算样本数据的方差。如果样本的大小 n = 0 n=0 ,那么我们认为 S 2 = X = 0 S2=X=0

题目解析

a v e ave 为平均数, k k 为有多少对, t [ i ] t[i] 为有每对的值对,答案是

A N S = ( a v e a v e k + s u m ( t [ i ] 2 ) 2 a v e s u m ( t [ i ] ) ) / k ANS=(ave*ave*k+sum(t[i]^2)-2*ave*sum(t[i]))/k

由此可知,不用得到每个 t [ i ] t[i] ,只要知道所有 t [ i ] t[i] 的和以及平方和。

a [ i ] a[i] 为每对的位置, c n t [ i ] cnt[i] 为有多少个片段与 i i 的相同, s u m [ i ] sum[i] t [ i ] t[i] 的和, s q r [ i ] sqr[i] t [ i ] t[i] 的平方和

s u m [ a [ i ] ] + = c n t [ a [ i ] ] i s u m s [ a [ i ] ] sum[a[i]]+=cnt[a[i]]*i-sums[a[i]] {加入第 i i 段时更新 t [ i ] t[i] 的和}

s q r [ a [ i ] ] + = c n t [ a [ i ] ] i i + s q r s [ a [ i ] ] 2 i s u m s [ a [ i ] ] sqr[a[i]]+=cnt[a[i]]*i*i+sqrs[a[i]]-2*i*sums[a[i]] {根据平方和公式,加入第 i i 段时更新 t [ i ] t[i] 的平方和}

最后化简公式可得 a n s = ans= 所有 t [ i ] t[i] 的平方和 t [ i ] -t[i] 和的平方

代码

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int T;
long long a[N],cnt[N],sqrs[N],sums[N],sum[N],sqr[N],gs,x,y;
double ans;
char c[N];
string s;
int main()
{
	freopen("tri.in","r",stdin);
	freopen("tri.out","w",stdout);
	scanf("%d",&T);
	while(T--)
	{
	  for(int i=111;i<=444;i++)
	   sqr[i]=sum[i]=sqrs[i]=sums[i]=cnt[i]=0; 
	  scanf("%s",c);
	  s=c;
	  for(int i=0;i<s.size();i++)
	   if(s[i]=='A') a[i]=1;
	   else if(s[i]=='G') a[i]=2;
	   else if(s[i]=='C') a[i]=3;
	   else a[i]=4;
	  for(int i=0;i<s.size()-2;i++)
	   a[i]=a[i]*100+a[i+1]*10+a[i+2];
	  for(int i=0;i<s.size()-2;i++)
	  {
	  	sqr[a[i]]+=cnt[a[i]]*i*i+sqrs[a[i]]-2*i*sums[a[i]]; 
	  	sum[a[i]]+=cnt[a[i]]*i-sums[a[i]];
	  	sqrs[a[i]]+=(long long)i*i;
	  	sums[a[i]]+=i;
	  	cnt[a[i]]++;
	  }
	  gs=x=y=ans=0;
	  for(int i=111;i<=444;i++)
	   gs+=cnt[i]*(cnt[i]-1)/2,x+=sqr[i],y+=sum[i];
	  if(gs==0) ans=0;
	  else ans=(1.0*x/gs)-(1.0*y/gs)*(1.0*y/gs);
	  printf("%0.6lf\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_43909855/article/details/89408662