【59测试】【树】【dp】
第一题 A :
这棵树由n个节点以及n - 1条有向边构成,每条边都从父亲节点指向儿子节点,保证除了根节点以外的每个节点都有一个唯一的父亲。树上的节点从1到n标号。该树的一棵子树的定义为某个节点以及从该节点出发能够达到的所有节点的集合,显然这棵树共有n棵子树。小A认为一棵有根树是美丽的当且仅当这棵树内节点的标号构成了一个连续的整数区间。现在小A想知道这棵树上共有多少棵美丽的子树。
解:
拿到这道题就一下子冒出来一个想法,记录每一个节点开始的子树的节点最大值、最小值,和节点数。如果max-min+1=sum,那么就成立。于是半个小时后,我就解决了第一题。看来好的想法很重要。自己就冒出来了,还不需要想。
其实也是一个dp。只不过我又用的dfs。
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define maxn 100005
using namespace std;
struct tree{
int sum,ma,mi;
};
tree f[maxn];
int n,ans;
int tot,he[maxn],ne[maxn],to[maxn];
bool r[maxn];
void add(int a,int b)
{
tot++;ne[tot]=he[a];to[tot]=b;he[a]=tot;
if (!f[a].sum) f[a].sum=;
if (!f[b].sum) f[b].sum=;
if (!f[a].ma) f[a].ma=f[a].mi=a;
if (!f[b].ma) f[b].ma=f[b].mi=b;
}
void dfs(int x)
{
for (int i=he[x];i;i=ne[i])
{
int t=to[i];
dfs(t);
f[x].sum+=f[t].sum;
if (f[t].ma>f[x].ma) f[x].ma=f[t].ma;
if (f[t].mi<f[x].mi) f[x].mi=f[t].mi;
}
if (f[x].ma-f[x].mi+==f[x].sum) ans++;
}
int main()
{
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
cin>>n;
for (int i=;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
r[b]=true;
add(a,b);
}
for (int i=;i<=n;i++)
if (!r[i]){//root
dfs(i);break;
}
printf("%d",ans);
return ;
}
第二题 B :
对于一个排列,考虑相邻的两个元素,如果后面一个比前面一个大,表示这个位置是上升的,用I表示,反之这个位置是下降的,用D表示。如排列3,1,2,7,4,6,5可以表示为DIIDID。
现在给出一个长度为n-1的排列表示,问有多少种1到n的排列满足这种表示。
解:
写不来正解,直接用暴力搜索20%,还被卡了一个点,只有10分。
正解: 用 dp[i][j]表示前 i 个数的第 i 位(最后这一位)放 j 的方案数。(假设前 i 位只放1~ i 数字)有三种情况:
I :第i 位的j 要比上一位大,所以由∑ dp[i-1][k] (1<=k<=j-1) 推来,因为有可能 j 数字在之前填过了,但是不影响结果,因为我们可以认为所有填的>=j的数字都+1,还保证了情况的全面性(即前 i 位可以填> i 的数字)。
D:第 i 位的 j 要比上一位小,所以由∑ dp[i-1][k] (j<k<i-1) 推来,同样的道理,j 数字也可能填过了,也可以认为+1.
?:无所谓第 i 位上的数,可以把以上两种情况的方案数加起来。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 1000000007
#define ll long long
using namespace std;
ll dp[5][1005],idx=1,cur=0,ans;
int main()
{
freopen("B.in","r",stdin);
freopen("B.out","w",stdout);
char c=getchar();
dp[0][1]=1;
while (c=='I'||c=='D'||c=='?')
{
cur^=1;idx++;
for (int i=1;i<=idx-1;i++)
{
dp[cur^1][i]+=dp[cur^1][i-1]%M;
dp[cur][i]=0;
}
if (c!='D'){
for (int i=2;i<=idx;i++)
dp[cur][i]=dp[cur^1][i-1]%M;
}
if (c!='I'){//不加else
for (int i=1;i<idx;i++)
dp[cur][i]+=((dp[cur^1][idx-1]-dp[cur^1][i-1])%M+M)%M;
}
c=getchar();//***
}
for (int i=1;i<=idx;i++)
ans=(ans+dp[cur][i])%M;
cout<<ans;
return 0;
}
第三题 C :
两个字符串分别为X,Y。小A非常开心,但在开心之余她还想考考小K。小A定义L为X与Y的最长公共子序列的长度(子序列在字符串内不一定连续,一个长度为L的字符串有2^L个子序列,包括空子序列)。现在小A取出了X的所有长度为L的子序列,并要求小K回答在这些子序列中,有多少个是Y的子序列。因为答案可能很大,所以小K只需要回答最终答案模10^9 + 7。
解:
首先是一个预处理LCS。然后再dp答案。
LCS:最长公共子序列。用n^2的方法算。
for (int i=1;i<=lena;i++)
for (int j=1;j<=lenb;j++)
{
lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]);
if (a[i]==b[j]) lcs[i][j]=max(lcs[i][j],lcs[i-1][j-1]+1);
}
然后f[i][j]表示:A串的前 i 个,B 串的前 j 个长度为lcs[i][j]的答案。对于A[i]:
1.没有新贡献,直接是f[i-1][j]
2.由新贡献,即选择 i 后,答案会改变。这时,当 离 j 最近的==A[i]的字符所在位置 p,如果lcs[i-1][p-1]+1==lcs[i][j]则说明,i 加入后,又可以在B 串中找到一个新的答案f[i-1][p-1]。
动态规划比较抽象,所以不容易理解,打表可以帮助理解,还有就是基础不是很牢,没有形成动态规划的基本脑回路。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1005
#define M 1000000007
using namespace std;
int lena,lenb,lcs[maxn][maxn],f[maxn][maxn];
int pos[30],pre[maxn][30];
char a[maxn],b[maxn];
int main()
{
freopen("C.in","r",stdin);
freopen("C.out","w",stdout);
scanf("%s",a+1);scanf("%s",b+1);
lena=strlen(a+1);lenb=strlen(b+1);
for (int i=1;i<=lena;i++)
for (int j=1;j<=lenb;j++)
{
lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]);
if (a[i]==b[j]) lcs[i][j]=max(lcs[i][j],lcs[i-1][j-1]+1);
}
memset(pre,-1,sizeof(pre));
for (int i=1;i<=lenb;i++)
{
pos[b[i]-'a']=i;
for (int j=0;j<26;j++)
pre[i][j]=pos[j];
}
for (int i=0;i<=lena;i++) f[i][0]=1;
for (int i=0;i<=lenb;i++) f[0][i]=1;
for (int i=1;i<=lena;i++)
for (int j=1;j<=lenb;j++)
{
if (lcs[i][j]==lcs[i-1][j]) f[i][j]=(f[i][j]+f[i-1][j])%M;
int p=pre[j][a[i]-'a'];
if (p!=-1&&lcs[i-1][p-1]+1==lcs[i][j]) f[i][j]=(f[i][j]+f[i-1][p-1])%M;
}
printf("%d",f[lena][lenb]);
return 0;
}
【59测试】【树】【dp】的更多相关文章
- [CSP-S模拟测试]:卡常题/b(基环树+DP)
题目描述 $ρ$有一个二分连通无向图,$X$方点.$Y$方点均为$n$个(编号为$1\sim n$).这个二分图比较特殊,每一个$Y$方点的度为$2$,一条黑色边,一条白色边.所有黑色边权值均为$a$ ...
- HDU4916 Count on the path(树dp??)
这道题的题意其实有点略晦涩,定义f(a,b)为 minimum of vertices not on the path between vertices a and b. 其实它加一个minimum ...
- CF456D A Lot of Games (字典树+DP)
D - A Lot of Games CF#260 Div2 D题 CF#260 Div1 B题 Codeforces Round #260 CF455B D. A Lot of Games time ...
- Codeforces 219D. Choosing Capital for Treeland (树dp)
题目链接:http://codeforces.com/contest/219/problem/D 树dp //#pragma comment(linker, "/STACK:10240000 ...
- HDU4276 The Ghost Blows Light SPFA&&树dp
题目的介绍以及思路完全参考了下面的博客:http://blog.csdn.net/acm_cxlove/article/details/7964739 做这道题主要是为了加强自己对SPFA的代码的训练 ...
- Tsinsen A1219. 采矿(陈许旻) (树链剖分,线段树 + DP)
[题目链接] http://www.tsinsen.com/A1219 [题意] 给定一棵树,a[u][i]代表u结点分配i人的收益,可以随时改变a[u],查询(u,v)代表在u子树的所有节点,在u- ...
- HDU 3016 Man Down (线段树+dp)
HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Ja ...
- bzoj 3572世界树 虚树+dp
题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...
- bzoj 2286 [Sdoi2011]消耗战 虚树+dp
题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...
- (纪念第一道完全自己想的树DP)CodeForces 219D Choosing Capital for Treeland
Choosing Capital for Treeland time limit per test 3 seconds memory limit per test 256 megabytes inpu ...
随机推荐
- 我去,徒弟半夜来电让写一个PHP短信验证(和群发)
感觉很纳闷啊,,..好几天几乎通宵了,今晚本来以为有个早觉睡,居然2点多才打电话来让帮忙... 记得前段时间还有博友问过同类的问题.... 名字我就隐藏掉了,呵呵,, 我在网上随便找了一个提供相应接口 ...
- 【final】站立会议---11.27
名称:nice! 组长:李权 成员:于淼 刘芳芳韩媛媛 宫丽君 时间:11月27日 13:00 项目内容:约跑app(约吧) 地点:传媒西楼220室 内容: 新任务的分配 1.李权分配任务 2.韩媛 ...
- SqlServer分区表概述(转载)
什么是分区表 一般情况下,我们建立数据库表时,表数据都存放在一个文件里. 但是如果是分区表的话,表数据就会按照你指定的规则分放到不同的文件里,把一个大的数据文件拆分为多个小文件,还可以把这些小文件放在 ...
- wex5 教程之 图文讲解 文件上传attachmentSimple(1)
视频教程地址:http://v.youku.com/v_show/id_XMTc4NDAyMTY4OA==.html 效果预览: 1 调用attchmentSimple组件,打开文件管理器,并选中,显 ...
- 十六、Swing高级组件
1.利用JTable类直接创建表格 (1)创建表格 构造方法:JTable(Object rowData,Object[] columnNames) (2)定制表格 编辑:isCellEditable ...
- 【Android】Spinner使用
Spinner:下拉列表,主要用于显示一些选项供用户选择,类似PC应用程序里面的Combobox. 使用Spinner需要以下条件: 1.一个 Spinner 控件 2.数据 3.一个Adapter ...
- 《BI项目笔记》创建标准维度、维度自定义层次结构
- 06-scanf函数
本文目录 变量的内存分析 scanf函数 回到顶部 一. 变量的内存分析 1. 字节和地址 为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”. 1> 内存以“字节为单 ...
- java方法参数
Java程序设计语言总是采用值调用.也就是说,方法得到的是所有参数的一个拷贝,特别是方法不能修改传递给它的任何参数变量的内容. 基本类型参数 1)X被初始化为percent值的一个拷贝: 2)X被乘以 ...
- XMPP学习记录之实战篇
在学习iOS以来一直想要研究即时聊天方面的技术,因工作原因此计划一直搁浅,近日偷得时闲开始着手与XMPP的学习.在学习之前我一直认为XMPP对我来说是一个很有难度的挑战,在了解了协议的具体形式后,才发 ...