【比赛】9.1

1>改造二叉树

一棵树,修改上面的数,使数成为二叉搜索树

即中序遍历严格递增

首先,排序二叉树是一种, 左儿子权值严格小于父亲, 右儿子权值严格大于父亲的二叉树(BST)。

所谓“排序”,就是中序遍历排序二叉树, 得到的是一个严格递增的序列。

那么我们显然要先中序遍历一趟,构造出A数组,

那么题目就变成求使一个序列变为严格递增,所需的最少修改次数

为了不去暴力看修改哪些点 我们转化思路,看可以留下哪些点

这里留下的点中, Aj−Ai>=j−i,

这个有点奇怪啊 再进一步转换:

扫描二维码关注公众号,回复: 7151722 查看本文章

a[i]-i 然后求最长非降子序列即可 

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n;
const int N=1e5+3;
int d[N],son[N][2];
int a[N],cnt;
int up[N];

void mid_dfs(int pos)
{
    if(son[pos][0]) mid_dfs(son[pos][0]);
    a[++cnt]=d[pos]-cnt;
    if(son[pos][1]) mid_dfs(son[pos][1]);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&d[i]);
    int f,ps;
    for(int i=2;i<=n;i++)
    {
        scanf("%d%d",&f,&ps);
        son[f][ps]=i;
    }
    mid_dfs(1);//简单一步,题目居然完全变样
    
    int sz=1;
    up[1]=a[1];
    for(int i=2;i<=cnt;i++)
    {
        int pos=upper_bound(up+1,up+sz+1,a[i])-up;//求非降序列,写upper,表示==的时候成立,>则修改 
        if(pos>sz) sz++;
        up[pos]=a[i];
    }
    
    printf("%d\n",n-sz);
    
    return 0;
}

2>两种交换元素的方案对比

交换元素,使序列有序,求最少交换次数

第一种是只能交换"相邻”元素,使序列有序,求最小交换次数,

假如是是序列升序,只需要求逆序对数

3 2 1-> 1 2 3 

3次

4 2 3 1 -> 1 2 3 4

2 3 1 4 (3)

2 1 3 4 (1)

1 2 3 4 (1)

正好对应每个数,和他右边数的逆序对个数

 

第二种是可以交换任意两个位置的元素,使之有序,求最小交换次数,

答案是: n-交换数字形成的环(置换环)的个数

(就是所有环中数据各自交换,的次数和)

比如 {5 1 3 2 4 7 6 8 } , 求将这个序列变成升序序列的最小交换次数,

那么这个序列中的环有{ 5,1,2,4},{7,6},{3},{8}, 那么最小交换次数就是 8-4,

 

求降序的最小交换次数,只需要将序列逆置,再进行求解 。

3>交换

复制自:https://www.cnblogs.com/Damitu/p/7646694.html

真是累了,不想打了

题解:
      ①顺着思考很麻烦,逆向考虑:最后一次交换发生的位置

      ②倒过来后,记忆化搜索,枚举当前状态的交换发生在哪个位置,然后区间一分为二处理子问题

      ③注意事项:交换可以发生的位置是左边和右边两部分都含有其应该有的数(顺序乱也可以)

      ④转移方程式:f[l][r]+=DFS(l,i)*DFS(i+1,r)*C[r-l-1][i-l]

            表示当前区间为[l,r],交换i,i+1,由于两边独立决策,所以存在一个组合关系,可以转化为有2n个空位放n个数的方案数,这样是因为每一边内部是有序的(这是一个重要结论)。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
const int N=53,mod=1e9+7;
int st[N],ed[N];

int c[N][N];
void prepare()
{
    c[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        c[i][0]=1;
        for(int j=1;j<=i;j++)
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    }
}

int ans;
long long jl[N][N];
long long dfs(int l,int r)
{
    if(jl[l][r]>=0) return jl[l][r];//神奇的加上记忆化 
    if(l==r) return jl[l][r]=1;
    
    jl[l][r]=0;
    for(int i=l;i<r;i++)
    {
        swap(st[i],st[i+1]);
        
        int j,k;
        for(j=l;j<=i;j++)
            if(st[j]>i) break;
        for(k=i+1;k<=r;k++)
            if(st[k]<=i) break;
        
        if(j>i && k>r)
        {
            long long ans1=dfs(l,i)*dfs(i+1,r)%mod;
            long long ans2=ans1*c[r-l-1][i-l]%mod;
            jl[l][r]=(jl[l][r]+ans2)%mod;
        }
        
        swap(st[i],st[i+1]);
    }
    return jl[l][r];
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&st[i]),ed[i]=i;
    
    prepare();
    memset(jl,-1,sizeof(jl));
    dfs(0,n-1);
    printf("%lld\n",jl[0][n-1]);
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xwww666666/p/11444379.html
9.1