码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 4783 Clumsy Algorithm

时间:2018-07-15 00:11:53      阅读:295      评论:0      收藏:0      [点我收藏+]

标签:algo   序列   efi   define   交换   scan   --   逆序   scanf   

题意不提。

  我们可以发现,可以将最终序列分为对于第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\n",++tt,f[n][n]);
		
	}
}

//代码来自某AC代码,侵删。

  

HDU 4783 Clumsy Algorithm

标签:algo   序列   efi   define   交换   scan   --   逆序   scanf   

原文地址:https://www.cnblogs.com/chadinblog/p/9311299.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!