zoukankan      html  css  js  c++  java
  • [GYM100134I][NEERC2012]Identification of Protein

    CXXI.[GYM100134I][NEERC2012]Identification of Protein

    debug5h,精神崩溃。

    首先,很容易想到把所有东西都乘上 \(10^5\) 变成整数。然后,因为 \(\gcd(9705276,12805858)=2\),所以在字符串长度 \(\leq400\) 时,每个值被表示成二者倍数之和的方式是唯一的。于是我们可以把所有合法的值唯一转换成“有 \(p_i\)P\(q_i\)Q”的表达形式。因此,整条字符串中所具有的 P 数和 Q 数也就确定了。分别设其为 \(n\)\(m\)

    然后,一条前缀就唯一对应了一条后缀,反之亦然。于是我们便可以建出一张矩阵,\(a_{i,j}\) 表示有多少个串中有 \(i\)P\(j\)Q(当然,作为前缀和后缀)。此时,一条字符串就对应了一条 \((0,0)\rightarrow(n,m)\) 的路径,而所有可以被表示成其前缀或后缀的值的数量就是路径经过所有位置的权值和。

    但是,一个值如果同时作为前缀和后缀出现,是不能被计算两遍的。所以我们设计DP状态时,要同时记录下正着的和反着的位置,以在上述情况时及时判断出来。我们设 \(f_{i,j,k}\) 表示当前填到前后缀各第 \(i\) 个字符,且前缀里已经填了 \(j\)P,后缀里已经填了 \(k\)Q 的最优收益。采取记忆化搜索进行DP,复杂度 \(O(n^3)\)

    要注意一堆细节,例如实际上当总串长度为奇或偶时,前后缀相遇处时的处理是不一样的。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int P=9705276;
    const int Q=12805858;
    const int inf=-0x3f3f3f3f;
    int q,n,m,s,g[410][410],f[210][210][210],opt[210][210][210];
    ll a[100100],mx;
    double db;
    pair<int,int>pr;
    pair<int,int>pt(ll ip){
    	for(int i=0;ip>=0;ip-=P,i++)if(!(ip%Q))return make_pair(i,ip/Q);
    	return make_pair(-1,-1);
    }
    int dfs(int stp,int x1,int x2){
    	int &now=f[stp][x1][x2];
    	if(now!=-1)return now;
    	if((x1+x2-(s&1)>n||stp-x1+stp-x2-(s&1)>m)||!(x1<=n&&x2<=n&&stp-x1<=m&&stp-x2<=m))return now=inf;
    	now=g[x1][stp-x1];
    	if(x1!=x2&&(x1!=n-x2||stp-x1!=m-(stp-x2)))now+=g[x2][stp-x2];
    	if(stp==((s+1)>>1))return now;
    	if(x1+x2>n||stp-x1+stp-x2>m)return now=inf;
    	int A=dfs(stp+1,x1,x2);
    	int B=((s&1)&&(stp==(s>>1)))?inf:dfs(stp+1,x1+1,x2);
    	int C=((s&1)&&(stp==(s>>1)))?inf:dfs(stp+1,x1,x2+1);
    	int D=dfs(stp+1,x1+1,x2+1);
    	int M=max({A,B,C,D});
    	now+=M;
    	if(A==M)opt[stp][x1][x2]=1;
    	else if(B==M)opt[stp][x1][x2]=2;
    	else if(C==M)opt[stp][x1][x2]=3;
    	else if(D==M)opt[stp][x1][x2]=4;
    	return now;
    }
    char res[410];
    int main(){
    	freopen("identification.in","r",stdin);
    	freopen("identification.out","w",stdout);
    	scanf("%d",&q),memset(f,-1,sizeof(f));
    	for(int i=1;i<=q;i++){
    		scanf("%lf",&db);
    		a[i]=db*100000+0.1;
    		mx=max(mx,a[i]);
    	}
    	pr=pt(mx),n=pr.first,m=pr.second,s=n+m;
    	for(int i=1;i<=q;i++){
    		pr=pt(a[i]);
    		if(pr==make_pair(-1,-1))continue;
    		if(pr.first>n||pr.second>m)continue;
    		g[pr.first][pr.second]++;
    		if((pr.first<<1)!=n||(pr.second<<1)!=m)g[n-pr.first][m-pr.second]++;
    	}
    	dfs(0,0,0);
    	for(int stp=0,x1=0,x2=0;stp+1<=s-stp;stp++){
    		if(opt[stp][x1][x2]==1)res[stp+1]='Q',res[s-stp]='Q';
    		else if(opt[stp][x1][x2]==2)res[stp+1]='P',res[s-stp]='Q',x1++;
    		else if(opt[stp][x1][x2]==3)res[stp+1]='Q',res[s-stp]='P',x2++;
    		else if(opt[stp][x1][x2]==4)res[stp+1]='P',res[s-stp]='P',x1++,x2++;
    	}
    	printf("%s\n",res+1);
    	return 0;
    }
    

  • 相关阅读:
    go开发 modules 的使用和代理
    利用 nodejs 解析 m3u8 格式文件,并下 ts 合并为 mp4
    别再@官方啦,普天同庆加国旗
    vue基于 element ui 的按钮点击节流
    react-router 5.0 的鉴权
    slot 组件的内部传值 v-slot 的使用
    javascript 写一个ajax 自动拦截,并下载数据
    Linux 命令大全
    http 基础
    MongoDB Shell (mongo)
  • 原文地址:https://www.cnblogs.com/Troverld/p/14601385.html
Copyright © 2011-2022 走看看