最近突然发现自己真的好弱,刷题量真的好少,代码能力明显不足,于是决定狂刷题目,现在暂时按照hdu的分类刷一刷,不管难易,先提高一下自己的思维和代码能力。
今天过的题目:
Hdu 1080、1087、1081、1114、4705、1159.
Hdu 1080 简单dp递推,前缀和
Hdu 1087 简单dp递推
Hdu 1081 最大子矩阵和
Hdu 1114 简单dp递推(怎么感觉像个背包?!)
Hdu 4705 树形dp
Hdu 1159 最长公共子序列
Hdu 1165 打表找规律
Hdu 4705:
计算某棵子树(根结点为u)时分三种情况讨论:
①A、B、C分别属于u的三棵子树
②其中一个点为u,剩下两个点在u的某一棵子树上
③其中两个点在u的同一棵子树上,另一个在另一棵子树上
刚好前天在bc上看到一种计数方法,类似得用到这道题上,简化了好多,so good!
//Hdu 4705
#pragma comment(linker, "/STACK:16777216")
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll siz[N], siz2[N];
ll ans;
vector<int>G[N];
void Init(int n)
{
for(int i=0; i<=n; ++i)
{
G[i].clear();
}
ans=0;
}
void AddEdge(int a, int b)
{
G[a].push_back(b);
G[b].push_back(a);
}
void dfs(int u, int fa)
{
siz[u]=1;
siz2[u]=0;
for(int i=0; i<G[u].size(); ++i)
{
int v=G[u][i];
if(v==fa) continue;
dfs(v, u);
ans+=siz2[u]*siz[v]+siz2[v]*siz[u];
siz2[u]+=siz2[v]+(siz[u]-1)*siz[v];
siz[u]+=siz[v];
}
}
int main()
{
int n;
while(~scanf("%d", &n))
{
Init(n);
for(int i=0; i<n-1; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
AddEdge(x, y);
}
dfs(1, 0);
printf("%I64d\n", ans);
}
return 0;
}
Hdu 1165:
一开始以为直接记忆话搜索,结果很快发现爆栈了,因为f(m, n)当m=3, n=23时,f(3, 23)=67108861, 这时候去算f(2, f(3, 23))肯定是跑不出来的,最后打表发现,当m等于2时,f(m, n)=2*n+3,当m等于1时,f(m, n)=n+2,然后根据m=3时的计算公式,直接退出f(3,n)就可以了。
#include<cstdio>
using namespace std;
const int N=33;
typedef long long ll;
ll dp[N];
ll f(int m, int n)
{
if(m==1) return n+2;
if(m==2) return 2*n+3;
return dp[n];
}
void init()
{
for(int i=0; i<=24; ++i)
{
if(!i) dp[i]=f(2, 1);
else dp[i]=2*dp[i-1]+3;
}
}
int main()
{
init();
int n, m;
while(~scanf("%d%d", &m, &n))
{
printf("%I64d\n", f(m, n));
}
return 0;
}