[POJ2440]DNA(dp)
来源:互联网 发布:慕课网python教程下载 编辑:程序博客网 时间:2024/06/16 21:31
题目描述
传送门
题意:给定一个长度L,求长度为L的01串不包含101和111的有多少个。
题解
算法一
这题在openjudge上的范围是
设f(i,a,b)表示前i位,最后两位为a,b(a,b=0/1)的方案数。那么f(i,b,a)=(f(i,b,a)+f(i-1,c,b))%Mod;其中保证cba!=101并且cba!=111。
这个dp是很显然的。因为要保证每一次在最后一位放的时候和前面没有冲突,那么就要记录后两位。
时间复杂度
算法二
但是在POJ上的范围是
是时候来一波奇技淫巧了。
考虑当长度不变时,方案数是不变的。将两段合成一段的时候,只需要将它们各自的方案数相乘就可以了。
那么如果我们把长度L分成
设m=
设f(i,a,b,c,d)表示前i位,其中最前面两位为ab,最后两位为cd(a,b,c,d=0/1)的方案数,那么我们可以在
设q(i,a,b)表示前i个块,最后两位为ab(a,b=0/1)的方案数,那么q(i,e,l)=(q(i,e,l)+q(i-1,a,b)*f(m,c,d,e,l))%Mod;其中保证abc!=101,abc!=111,bcd!=101,bcd!=111。同样是保证不冲突。
求出了q(t,a,b)之后,块有可能不是整个的,也就是说在最后一个块的后面有可能有一些没算过的位置。但是数量同样是
那么我们终于求出了正确的解!时间复杂度
算法三
当我打完愚蠢的多维dp了之后看题解= =
递推式:f(n)=f(n-1)+f(n-3)+f(n-4)
其实想一想就能明白它的正确性:
f(n-1)实际上是往最后一位加了一个0。
最后一位只有一个数,只有0/1两种情况。
最后加一个0是一定不会引起冲突的对吧?但是最后加一个1就不一定了,如果前面是10的话就变成了101就会变成不合法的了。所以将f(n-1)加一遍。
f(n-3)实际上是往最后3位上加了一个011。
最后三位实际上有这么多种情况:
001 010 100 011 101 110 111
可以发现第2、3、6种情况在f(n-1)里就已经包括了;第5、7种情况是不合法的;第2种情况如果它前面是1的话就会变成1010有可能变成不合法的情况所以淘汰掉。于是最后三位就只剩下了一种011的情况,所以只将f(n-3)加一遍。
f(n-4)实际上是往最后四位加了一个0001。
和上面的方法相同,列举一下就会发现除了0001,其余所有的情况要么不合法,要么已经被之前的情况包括了。
而f(n-5)就没有意义了,因为它所有的情况不是被前面的包括了就是不合法。
这就是这个递推式的由来。
好劲啊!
而且f特别像fibnacci的递推公式对吧?那么就是说如果存在
代码
这里是暴力dp。
#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define Mod 2005int n;long long f[1000005][2][2],ans;void clear(){ memset(f,0,sizeof(f)); ans=0;}int main(){ while (~scanf("%d",&n)) { clear(); if (n==1) { puts("2"); continue; } f[2][0][0]=f[2][0][1]=f[2][1][0]=f[2][1][1]=1; for (int i=3;i<=n;++i) for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) for (int c=0;c<=1;++c) if (!(c==1&&b==0&&a==1)&&!(c==1&&b==1&&a==1)) f[i][b][a]=(f[i][b][a]+f[i-1][c][b])%Mod; ans=(f[n][0][0]+f[n][0][1]+f[n][1][0]+f[n][1][1])%Mod; printf("%d\n",ans); }}
#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define Mod 2005int n,m,p,t,base;int a[16]={0,2,4,6,9,15,25,40,64,104,169,273,441,714,1156,1870};int f[10005][2][2][2][2],g[2][2][2][2],h[10005][2][2],q[10005][2][2],ans;void clear(){ memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); memset(h,0,sizeof(h)); memset(q,0,sizeof(q)); m=p=t=base=ans=0;}int main(){ while (~scanf("%d",&n)) { clear(); if (n<16) { printf("%d\n",a[n]); continue; } m=sqrt(n); p=n%m; t=n/m; for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) for (int c=0;c<=1;++c) for (int d=0;d<=1;++d) if (!(a==1&&b==0&&c==1)&&!(a==1&&b==1&&c==1)&&!(b==1&&c==0&&d==1)&&!(b==1&&c==1&&d==1)) f[4][a][b][c][d]=1; for (int i=5;i<=m;++i) for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) for (int c=0;c<=1;++c) for (int d=0;d<=1;++d) for (int e=0;e<=1;++e) if (!(c==1&&d==0&&e==1)&&!(c==1&&d==1&&e==1)) f[i][a][b][d][e]=(f[i][a][b][d][e]+f[i-1][a][b][c][d])%Mod; for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) for (int c=0;c<=1;++c) for (int d=0;d<=1;++d) { g[a][b][c][d]=f[m][a][b][c][d]; q[1][c][d]=(q[1][c][d]+f[m][a][b][c][d])%Mod; } for (int i=2;i<=t;++i) for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) for (int c=0;c<=1;++c) for (int d=0;d<=1;++d) for (int e=0;e<=1;++e) for (int l=0;l<=1;++l) if (!(a==1&&b==0&&c==1)&&!(a==1&&b==1&&c==1)&&!(b==1&&c==0&&d==1)&&!(b==1&&c==1&&d==1)) q[i][e][l]=(q[i][e][l]+q[i-1][a][b]*g[c][d][e][l])%Mod; if (p) { base=m*t; for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) h[0][a][b]=q[t][a][b]; for (int i=m*t+1;i<=n;++i) for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) for (int c=0;c<=1;++c) if (!(a==1&&b==0&&c==1)&&!(a==1&&b==1&&c==1)) h[i-base][b][c]=(h[i-base][b][c]+h[i-1-base][a][b])%Mod; for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) ans=(ans+h[n-base][a][b])%Mod; } else { for (int a=0;a<=1;++a) for (int b=0;b<=1;++b) ans=(ans+q[t][a][b])%Mod; } printf("%d\n",ans); }}
傻逼dp我没有写。可能是因为看到递推式了之后感到自己太傻逼于是弃疗了。
总结
①分块dp第一次写。自己想出来写出来还是很开心的。
②递推式非常厉害啊。这种东西应该自己好好想一想。
- [POJ2440]DNA(dp)
- DNA poj2440
- [BZOJ4606][Apio2008]DNA(dp)
- poj 3691 DNA repair(自动机+DP)
- hdu2457 DNA repair(AC自动机+dp)
- [SCU 4501] DNA序列 (状压DP)
- [POJ 1795] DNA Laboratory (状压DP)
- hdu DNA repair(AC自动机+DP)
- bzoj 4606: [Apio2008]DNA (DP)
- 【POJ1795】DNA Laboratory(状态压缩DP)
- [DP] DNA(基因重组) (DNA)
- DNA Sequences,dp
- DNA比对(DP)
- HDU 2457 DNA repair(AC自动机+DP)
- DNA序列 (各点只出现1次的Dp序)
- HDU 2457 DNA repair(AC自动机 + DP 入门)
- 字符串练习题: 【HDU 2457】 DNA repair(AC自动机+DP)
- poj 3691 DNA repair(AC自动机+dp)
- Java 集合深入理解(11):LinkedList
- 打膈膜 【NOIP2016提高A组模拟10.15】
- JS 之函数定义 & 创建对象 三种方式
- UGUI的点击事件的学习
- 条件断点 设置 出现异常
- [POJ2440]DNA(dp)
- src 和 href 的区别
- hdu 2639 Bone Collector II(0-1 + 路径)
- Multi-Samples AA
- 欧拉函数(森林里的树,uva 10214)
- sha1散列算法
- Neural Networks and Deep Learning CH3
- java单例设计模式实例总结
- android多线程下载