zoukankan      html  css  js  c++  java
  • HDU 4783 Clumsy Algorithm

    题意不提。

      我们可以发现,可以将最终序列分为对于第i个位置i-pi>=0与i-pi<0种两个子序列。且如果f[n]==g[n],则有两个子序列都递增。

      原因是f[n]表示1-n这个排列的逆序对个数,即冒泡排序的交换次数,而每个g[i]表示将p[i]从i位置移到它应当在的p[i]位置的交换次数。

      考虑将每个满足i-p[i]>0的p[i]从i位置移到p[i]位置是正确的条件,显然对于i-p[i]>0的每个p[i]必须递增,否则,会产生p[i]与p[j]交换时的交叉,使冒泡的代价增大。

      若 i-p[i]<0 的p[i]不递增,它们之间会产生新的冒泡,使冒泡的代价增加。

      所以就是DP了,设f[i][j]表示已放了j个数,其中最大数为i的且满足限制的方案数,显然如果j+1的位置放i-p[i]<0的,直接枚举i+1-n的数字即可。

      若j+1的位置放i-p[i]>=0的数字,由于i-p[i]>=0的数字必须递增,且i递增,因此有一个必选的数字直接填入即可。

      直接转移即可。

      

    #include<bits/stdc++.h>
    #define MOD 1000000007
    using namespace std;
    #define FILE "chad"
    set<int> S;
    int n, k, f[105][105];
    
    int main()
    {
    	//freopen(FILE".in","r",stdin);
    	//freopen(FILE".out","w",stdout);
    	int T; scanf("%d",&T);
    	for(int tt = 0;T--;)
    	{
    		memset(f, 0, sizeof f);
    		S.clear();
    	
    		scanf("%d%d",&n,&k);
    		for(int i = 1; i <= n; i++) S.insert(i);
    		int mx = 0, flag = 1;
    		for(int i = 1; i <= k; i++)
    		{
    			int x; scanf("%d",&x);
    			if(x > mx)
    			{
    				mx = x;
    				
    			}
    			else if(x != *S.begin()) flag = 0;
    			S.erase(x);
    		}
    		f[mx][k] = flag;
    		for(int i = 0; i <= n; i++)
    		{
    			for(int j = 0; j < n; j++)
    			{
    				if(i-j > 0) (f[i][j+1] += f[i][j]) %= MOD;
    				for(int k = i+1; k <= n; k++)
    					(f[k][j+1] += f[i][j]) %= MOD;
    			}
    		}
    		printf("Case #%d: %d
    ",++tt,f[n][n]);
    		
    	}
    }
    
    //代码来自某AC代码,侵删。
    

      

  • 相关阅读:
    022、如何运行容器(2019-01-15 周二)
    ssh 跳板机部署
    021、镜像小结(2019-01-14 周一)
    020、搭建本地Registry(2019-01-11 周五)
    019、使用公共Registry (2019-01-10 周四)
    018、容器命名最佳实践 (2019-01-09 周三)
    017、RUN、CMD、ENTRYPOINT (2019-01-08 周二)
    016、Dockerfile 常用命令(2019-01-07 周一)
    015、调试Dockerfile(2019-01-04 周五)
    014、镜像的缓存特性(2019-01-03 周四)
  • 原文地址:https://www.cnblogs.com/chadinblog/p/9311299.html
Copyright © 2011-2022 走看看