• 排序工作量之新任务(SHOI2001)


    排序工作量之新任务(SHOI2001)

    给出两个整数n和t,求n的全排列中逆序对数为t的个数,和逆序对数为t的字典序最小全排列。

    首先第一个问题可以用dp解决,(f[i][j])表示前i个数,j个逆序对的序列数,那么(f[i][j]=f[i-1][j-k] (k<i)(kle j))

    易证明一个全排列,交换值差1的两个数,逆序对个数+或-1。同时可以推出逆序对数为t时的字典序最小全排列,一定一个严格上升,公差为1的序列,后面接上两个严格下降,公差为1的序列,并且后面两个序列衔接处差2。因此从后往前处理,不停交换当前数与后面的一个数即可。具体怎么实现请看代码。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int maxn=25;
    int n, t;
    long long f[maxn][maxn*maxn];
    int a[maxn];
    
    int main(){
    	scanf("%d%d", &n, &t);
    	if (t==0){
    		puts("1");
    		for (int i=1; i<=n; ++i) printf("%d ", i);
    		return 0; }
    	f[1][0]=f[2][0]=f[2][1]=1;
    	for (int i=3; i<=n; ++i)
    		for (int j=0; j<=i*(i-1)/2; ++j)
    			for (int k=0; k<i&&k<=j; ++k)
    			f[i][j]+=f[i-1][j-k];
    	printf("%lld
    ", f[n][t]);
    	for (int i=1; i<=n; ++i) a[i]=i;
    	for (int i=n-1; i>=1; --i){
    		for (int j=n; j>i; --j){
    			swap(a[i], a[j]);
    			if (!(--t)) break;
    		} if (!t) break;
    	}
    	for (int i=1; i<=n; ++i) printf("%d ", a[i]);
    	return 0;
    }
    
  • 相关阅读:
    DateTime.now()用法
    C#中静态类详述
    面向对象详述
    解决Github打不开问题
    git 提交代码流程 先暂存 在提交+备注 然后拉取代码获取最新的代码 然后再推送 git push
    常用
    样式重置
    Html 5优化
    理解js闭包
    css 倒计时 svg
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/9010988.html
Copyright © 2020-2023  润新知