20161107的考试】树论基础,计数dp,字符串计数dp

来源:互联网 发布:淘宝改后台软件 编辑:程序博客网 时间:2024/06/03 19:38

……DP专场引发的血案【xxx

………………今天如果是NOIP那我就退役了【x

……虽然的确是noipd考试范围内【跪地不起


T1:

题意:有根树,点有标号,求有多少棵子树上的编号是连续的一段整数

思路:记录每棵子树的size,minlable和maxlable,算一下就好了

代码:

#include<bits/stdc++.h>#define MAXN 100005using namespace std;int n;vector<int> son[MAXN];int ind[MAXN];int cnt = 0,root;int siz[MAXN];int mn[MAXN],mx[MAXN];void dfs(int now) {mx[now] = mn[now] = now;siz[now] = 1;for (int i=0;i<son[now].size();++i) {int aim = son[now][i];dfs(aim);siz[now] += siz[aim];if(mx[aim] - mn[aim] + 1 == siz[aim])++cnt;mx[now] = max(mx[now],mx[aim]);mn[now] = min(mn[now],mn[aim]);}}int read_x,read_y;int main() {freopen("A.in","r",stdin);freopen("A.out","w",stdout);scanf("%d",&n);for (int i=1;i<n;++i)scanf("%d%d",&read_x,&read_y),son[read_x].push_back(read_y),++ind[read_y];for (int i=1;i<=n;++i)if(!ind[i]) {root = i;break;}dfs(root);printf("%d",cnt+1);return 0;}

T2

题意:对于一个1~n的排列,可以用两个数之间的大于小于关系来表示,给出这个表示,求有多少1~n的排列满足这个表示

思路:GG

         反正我先考虑的是数位dp一样的递推东西【大概是递推写多了的后遗症QAQ】……然后判去重啥的想了一年发现还是n^3的复杂度……GG

         最后……发现,转移和递推式基本一样【跪地不起】,区别就是初始化那儿……

         反正递推啥的就是用f[i][j]表示第i位填j的话有多少方案,然后枚举下一位填的合法的转移过去;如果没有限制每个数只出现一次显然这么搞。

         然而限制了次数的话,还是想f[i][j],但是是表示填了前i位,且第i位填的是填了的数中第j大的一个。……显然转移的时候无论如何都不会重…………嗯……完事了…………至于如何让转移变成……O(1)的……前缀和后缀和啥的瞎搞搞就好了

         于是感谢CYZ大爷又让我涨了姿势……这个前缀后缀和的写法我给满分【因为转移的时候系数都是1于是很显然了【

代码:

#include<bits/stdc++.h>#define MOD 1000000007#define MAXN 1010using namespace std;char s[MAXN];int n;int f[MAXN][MAXN];int main(){freopen("B.in","r",stdin);freopen("B.out","w",stdout);scanf("%s",s);n = strlen(s);f[1][1] = 1;for(int i=0;i<n;++i){int x = i+2;if(s[i]=='I'){for(int j=2;j<=x;++j)f[x][j] = f[x-1][j-1];for(int j=1;j<=x;++j)f[x][j] = (f[x][j] + f[x][j-1]) %MOD; }elseif(s[i]=='D'){for(int j=1;j<=x;++j)f[x][j] = f[x-1][j];for(int j=x;j;--j)f[x][j] = (f[x][j] + f[x][j+1])%MOD;}else{int tmp = 0;for(int j=1;j<=x;++j)(tmp += f[x-1][j]) %= MOD;for(int j=1;j<=x;++j)f[x][j] = tmp;}}int ans = 0 ;++n;for(int i=1;i<=n;++i)(ans += f[n][i]) %= MOD;printf("%d",ans);return 0;}

T3

题意:两个字符串s1,s2,设它们的最长公共子序列的长度为L,求s1中长度为L的子序列有多少个在s2中出现过

思路:……想了想lcs怎么写啊估计要yy一会儿……先磕T2,GG

           先求lcs,f[i][j]表示s1中前i个和s2中前j个的lcs长度。

           …………我还是粘题解吧……反正……就这个意思23333

首先用

0 0
原创粉丝点击