1>改造二叉树
一棵树,修改上面的数,使数成为二叉搜索树
即中序遍历严格递增
首先,排序二叉树是一种, 左儿子权值严格小于父亲, 右儿子权值严格大于父亲的二叉树(BST)。
所谓“排序”,就是中序遍历排序二叉树, 得到的是一个严格递增的序列。
那么我们显然要先中序遍历一趟,构造出A数组,
那么题目就变成求使一个序列变为严格递增,所需的最少修改次数
为了不去暴力看修改哪些点 我们转化思路,看可以留下哪些点
这里留下的点中, Aj−Ai>=j−i,
这个有点奇怪啊 再进一步转换:
将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-sz); return 0; }
2>交换
复制自: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 ",jl[0][n-1]); return 0; }