2/1 dp+区间dp+catalan数+Cayley公式
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2/1 dp+区间dp+catalan数+Cayley公式相关的知识,希望对你有一定的参考价值。
小重点:catalan数
典型数字:1,2,5,14,42,132,429……
典型题目:(一般都要用到高精度,可用python写)
多边形的三角形划分数目
括号分割数字
下三角形从左上角走到右下角
https://www.luogu.com.cn/problem/P2532
python版本:
a=input()
c=1
for i in range (a+2,a*2+1):
c=c*i
for i in range (1,a+1):
c=c/i
print (c)
特征:
A始终大于等于B
n和2*n都会出现
公式:h(n)=h(n−1)∗(4∗n−2)/(n+1)
https://www.luogu.com.cn/problem/P1754
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,ans,g,f[100][100];
signed main()
scanf("%d",&n);
for(int i=1;i<=n;i++)
f[i][0]=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
f[i][j]=f[i-1][j]+f[i][j-1];
cout<<f[n][n]<<endl;
return 0;
Cayley公式: CayleyCayley公式的定义是这样的,对于n n个不同的节点,能够组成的无根树(原来是无向连通图或者是有标志节点的树)的种数是n^n-2种
https://www.luogu.com.cn/problem/P4981
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+9;
int pow(int a,int p)
int res=1;
while(p)
if(p&1)
res=(res*a)%mod;
a=(a*a)%mod;
p>>=1;
return res;
signed main()
int t;scanf("%lld",&t);
while(t--)
int n;scanf("%lld",&n);
cout<<pow(n,n-1)<<endl;
return 0;
https://www.luogu.com.cn/problem/P3146
通过枚举分割点
直接考虑最后一个区间或者中间一个区间的合并情况
#include <bits/stdc++.h>
using namespace std;
const int maxn=405;
int a[maxn],dp[maxn][maxn],n,ans;
int main()
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp[i][i]=a[i];
for(int len=2;len<=n;len++)
for(int i=1,j=len;j<=n;i++,j++)
for(int k=i;k<j;k++)
if(dp[i][k]==dp[k+1][j])
dp[i][j]=max(dp[i][j],dp[i][k]+1);
ans=max(ans,dp[i][j]);
cout<<ans<<endl;
return 0;
https://www.luogu.com.cn/blog/635forever/solution-p3205
#include <bits/stdc++.h>
using namespace std;
const int mod=19650827;
const int maxn=4005;
int a[maxn],f[maxn][maxn][2],n,ans;
int main()
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
f[i][i][0]=1;
for(int len=2;len<=n;len++)
for(int i=1,j=len;j<=n;i++,j++)
if(a[j]>a[j-1])
f[i][j][1]+=f[i][j-1][1];
if(a[j]>a[i])
f[i][j][1]+=f[i][j-1][0];
if(a[i]<a[i+1])
f[i][j][0]+=f[i+1][j][0];
if(a[i]<a[j])
f[i][j][0]+=f[i+1][j][1];
f[i][j][0]%=mod;
f[i][j][1]%=mod;
cout<<(f[1][n][0]+f[1][n][1])%mod<<endl;
return 0;
https://www.luogu.com.cn/problem/P4170
#include <bits/stdc++.h>
using namespace std;
const int mod=19650827;
const int inf=0x3f3f3f3f;
const int maxn=105;
int a[maxn],f[maxn][maxn],n,ans=inf;
char s[55];
int main()
scanf("%s",s+1);
memset(f,inf,sizeof(f));
n=strlen(s+1);
for(int i=1;i<=n;i++)
f[i][i]=1;
for(int len=2;len<=n;len++)
for(int i=1,j=len;j<=n;i++,j++)
if(s[i]!=s[j])
//若不想等,则两个次数相加
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
else //若相等取一个最小值
f[i][j]=min(f[i+1][j],f[i][j-1]);
cout<<f[1][n]<<endl;
return 0;
https://www.luogu.com.cn/problem/P2858
经典DP做法:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2005;
int a[maxn],dp[maxn][maxn],n;
int main()
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++) //取了i个数
for(int j=0;j<=i;j++) //左边取了j个
int g=i-j; //右边将要取到g个数
dp[i][j]=max(dp[i-1][j]+a[n-g+1]*i,dp[i-1][j-1]+a[j]*i);
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,dp[n][i]);
cout<<ans<<endl;
return 0;
https://www.luogu.com.cn/problem/P1684
一个dp问题被贪心巧妙地解决了。。。
#include <bits/stdc++.h>
using namespace std;
int n,ans,g;
map<int,int>mp;
int main()
scanf("%d",&n);
for(int i=1;i<=n;i++)
int x;
scanf("%d",&x);
mp[x]++;
if(mp[x]==2)
g++;
if(g==2)
ans++;
mp.clear();
g=0;
if(mp[x]==4)
ans++;
mp.clear();
g=0;
cout<<ans<<endl;
return 0;
以上是关于2/1 dp+区间dp+catalan数+Cayley公式的主要内容,如果未能解决你的问题,请参考以下文章
noi 2.6_9288&hdu 1133Buy the Ticket(DP / 排列组合 Catalan+高精度)
P1005 [NOIP2007 提高组] 矩阵取数游戏(区间dp)