• 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代码,侵删。
    

      

  • 相关阅读:
    【PAT甲级】1034 Head of a Gang (30分):图的遍历DFS
    循环的嵌套
    0.1+07 !=0.8的原因
    java script-页面交互
    java script-逻辑分支
    java script-数据类型转换&&运算符
    java script概述
    浏览器内核
    网格布局
    让一个元素在父元素上下左右居中
  • 原文地址:https://www.cnblogs.com/chadinblog/p/9311299.html
Copyright © 2020-2023  润新知