zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 054

    C.Roughly Sorted

    题目描述

    如果一个排列每个位置上的逆序对个数都 (leq k),那么它是好排列。假设你有排列 (P),每次可以交换两个相邻元素,用最小的步数得到好排列 (P')

    现给定 (P')(k),求可能的 (P) 有多少个。

    (nleq 5000)

    解法

    首先考虑知道了排列 (P) 怎么求出排列 (P'),设第 (i) 个位置的逆序对个数是 (x_i),因为一次交换最多让逆序对减一,所以答案下界是 (sum_imax(x_i-k,0)),构造方法是每次找到最小的位置 (i) 满足 (p_{i-1}>p_i),并且 (x_i>k),把这两个位置交换一下,可以证明如果排列不合法一定能找到这样的位置。

    那么考虑用排列 (P') 还原出可能的 (P),首先我声明:如果我们知道了每个位置上的逆序对个数,那么对应的排列是唯一的。所以我们考察调整后的逆序对个数是否合法即可。

    对于 (x_i<k) 的位置是不能主动换的,因为交换让逆序对增加或减小都是不合法的,让他们的逆序对固定即可。对于 (x_i=k) 的位置逆序对是可以任意增加的,但就是不能减小,所以如果我们按照 (i=n...1) 的顺序考虑,我们可以把它右移任意步数,那么乘上 ((n-i+1)) 即可。

    总结

    最优策略问题也可以思考构造答案下界,但是首先一定要想清楚答案下界是什么。

    计数题中的转化要建立起对应关系,比如这题我们建立了逆序对和排列的对应关系,就把问题转化到逆序对上了。

    #include <cstdio>
    const int M = 5005;
    const int MOD = 998244353;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,k,ans=1,p[M],x[M];
    signed main()
    {
    	n=read();k=read();
    	for(int i=1;i<=n;i++)
    		p[i]=read();
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<i;j++)
    			x[i]+=(p[j]>p[i]);
    	for(int i=n;i>=1;i--)
    		if(x[i]==k) ans=1ll*ans*(n-i+1)%MOD;
    	printf("%d
    ",ans); 
    }
    
  • 相关阅读:
    hdu 2485 Destroying the bus stations 迭代加深搜索
    hdu 2487 Ugly Windows 模拟
    hdu 2492 Ping pong 线段树
    hdu 1059 Dividing 多重背包
    hdu 3315 My Brute 费用流,费用最小且代价最小
    第四天 下载网络图片显示
    第三天 单元测试和数据库操作
    第二天 布局文件
    第一天 安卓简介
    Android 获取存储空间
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15049588.html
Copyright © 2011-2022 走看看