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+高精度)

POJ2955区间DP

P1005 [NOIP2007 提高组] 矩阵取数游戏(区间dp)

HDU 4632 Palindrome subsequence(区间DP求回文子序列数)

luogu P1005 矩阵取数游戏 区间DP

HDU3555 区间的数里面有49的个数(数位dp)