UVA 10497 - Sweet Child Makes Trouble(DP+高精度)

题目链接:10497 - Sweet Child Makes Trouble

题意:n个物品,原来物品属于一个地方,现在要把物品重新放回去,问能放几种使得每个物品都与原来位置不同

思路:递推,一开始随便搞了个二维状态,dp[i][j]表示i个物品,有j个位置不同,那么dp[n][n]就是答案,递推式为:

dp[i][j] = 1 (j == 0)

dp[i][j] = (j - 1) * dp[i - 1][j - 1] + dp[i - 1][j] + (i - j + 1) * dp[i - 1][j - 2]; ( j > 1)

然后跑一下最大的n = 800,发现longlong都存不下,然后改高精度,发现加上高精度后这个状态是开不下的。

然后重新想状态,明显只够一维了,dp[i]表示i个物品的情况。

那么可以这样考虑,dp[i] 从 dp[i - 1]的状态过来,随便把一个位置和最后多上的那个位置对调就满足了,可行的位置一共有i - 1个,种数为(i - 1) * dp[i - 1];

dp[i]从dp[i - 2]状态过来,这样有两个相同的,把这两个位置交换一下也满足了,这位置一共也有i - 1个,种数为(i - 1) * dp[i - 2];

于是状态转移出来了,dp[i] = (i - 1) * ( dp[i - 1] + dp[i - 2]);

代码:

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
const int MAXN = 2005;

struct bign {
	int len, num[MAXN];

	bign () {
		len = 0;
		memset(num, 0, sizeof(num));
	}
	bign (int number) {*this = number;}
	bign (const char* number) {*this = number;}

	void DelZero ();
	void Put ();

	void operator = (int number);
	void operator = (char* number);

	bool operator <  (const bign& b) const;
	bool operator >  (const bign& b) const { return b < *this; }
	bool operator <= (const bign& b) const { return !(b < *this); }
	bool operator >= (const bign& b) const { return !(*this < b); }
	bool operator != (const bign& b) const { return b < *this || *this < b;}
	bool operator == (const bign& b) const { return !(b != *this); }

	void operator ++ ();
	void operator -- ();
	bign operator + (const int& b);
	bign operator + (const bign& b);
	bign operator - (const int& b);
	bign operator - (const bign& b);
	bign operator * (const int& b);
	bign operator * (const bign& b);
	bign operator / (const int& b);
	//bign operator / (const bign& b);
	int operator % (const int& b);
};

/*Code*/
bign dp[805];

int main() {
	dp[0] = 0; dp[1] = 0; dp[2] = 1;
	for (int i = 3; i <= 800; i++) {
		dp[i] = (dp[i - 1] + dp[i - 2]) * (i - 1);
 	}
 	int n;
 	while (~scanf("%d", &n) && n >= 0) {
 		dp[n].Put();
 		printf("\n");
  	}
	return 0;
}
void bign::DelZero () {
	while (len && num[len-1] == 0)
		len--;

	if (len == 0) {
		num[len++] = 0;
	}
}

void bign::Put () {
	for (int i = len-1; i >= 0; i--)
		printf("%d", num[i]);
}

void bign::operator = (char* number) {
	len = strlen (number);
	for (int i = 0; i < len; i++)
		num[i] = number[len-i-1] - ‘0‘;

	DelZero ();
}

void bign::operator = (int number) {

	len = 0;
	while (number) {
		num[len++] = number%10;
		number /= 10;
	}

	DelZero ();
}

bool bign::operator < (const bign& b) const {
	if (len != b.len)
		return len < b.len;
	for (int i = len-1; i >= 0; i--)
		if (num[i] != b.num[i])
			return num[i] < b.num[i];
	return false;
}

void bign::operator ++ () {
	int s = 1;

	for (int i = 0; i < len; i++) {
		s = s + num[i];
		num[i] = s % 10;
		s /= 10;
		if (!s) break;
	}

	while (s) {
		num[len++] = s%10;
		s /= 10;
	}
}

void bign::operator -- () {
	if (num[0] == 0 && len == 1) return;

	int s = -1;
	for (int i = 0; i < len; i++) {
		s = s + num[i];
		num[i] = (s + 10) % 10;
		if (s >= 0) break;
	}
	DelZero ();
}

bign bign::operator + (const int& b) {
	bign a = b;
	return *this + a;
}

bign bign::operator + (const bign& b) {
	int bignSum = 0;
	bign ans;

	for (int i = 0; i < len || i < b.len; i++) {
		if (i < len) bignSum += num[i];
		if (i < b.len) bignSum += b.num[i];

		ans.num[ans.len++] = bignSum % 10;
		bignSum /= 10;
	}

	while (bignSum) {
		ans.num[ans.len++] = bignSum % 10;
		bignSum /= 10;
	}

	return ans;
}

bign bign::operator - (const int& b) {
	bign a = b;
	return *this - a;
}

bign bign::operator - (const bign& b) {
	int bignSub = 0;
	bign ans;
	for (int i = 0; i < len || i < b.len; i++) {
		bignSub += num[i];
		bignSub -= b.num[i];
		ans.num[ans.len++] = (bignSub + 10) % 10;
		if (bignSub < 0) bignSub = -1;
	}
	ans.DelZero ();
	return ans;
}

bign bign::operator * (const int& b) {
	int bignSum = 0;
	bign ans;

	ans.len = len;
	for (int i = 0; i < len; i++) {
		bignSum += num[i] * b;
		ans.num[i] = bignSum % 10;
		bignSum /= 10;
	}

	while (bignSum) {
		ans.num[ans.len++] = bignSum % 10;
		bignSum /= 10;
	}

	return ans;
}

bign bign::operator * (const bign& b) {
	bign ans;
	ans.len = 0; 

	for (int i = 0; i < len; i++){
		int bignSum = 0;  

		for (int j = 0; j < b.len; j++){
			bignSum += num[i] * b.num[j] + ans.num[i+j];
			ans.num[i+j] = bignSum % 10;
			bignSum /= 10;
		}
		ans.len = i + b.len;  

		while (bignSum){
			ans.num[ans.len++] = bignSum % 10;
			bignSum /= 10;
		}
	}
	return ans;
}

bign bign::operator / (const int& b) {

	bign ans;

	int s = 0;
	for (int i = len-1; i >= 0; i--) {
		s = s * 10 + num[i];
		ans.num[i] = s/b;
		s %= b;
	}

	ans.len = len;
	ans.DelZero ();
	return ans;
}

int bign::operator % (const int& b) {

	bign ans;

	int s = 0;
	for (int i = len-1; i >= 0; i--) {
		s = s * 10 + num[i];
		ans.num[i] = s/b;
		s %= b;
	}

	return s;
}

UVA 10497 - Sweet Child Makes Trouble(DP+高精度),布布扣,bubuko.com

时间: 2024-10-08 00:10:48

UVA 10497 - Sweet Child Makes Trouble(DP+高精度)的相关文章

uva 10497 - Sweet Child Makes Trouble(dp+高精度)

题目链接:uva 10497 - Sweet Child Makes Trouble 题目大意:有个小屁孩很淘气,总是趁父母不在家的时候去拿家具玩,每次拿n个家具玩,但是放回去的时候一定不会将某个物品放回原处,一定要打乱.问说有多少放的方式满足. 解题思路:dp[i]表示说i个数打乱的情况,dp[i]=(dp[i?1]+dp[i?2])?(i?1)每次新增一个数,放在序列的最后一个位置,它的位置一定是正确的,所以一定要和前面i?1个的其中一个交换位置才可以,那么如果选中位置上的物品为错误归放的,

UVA - 10497 Sweet Child Makes Trouble

Children are always sweet but they can sometimesmake you feel bitter. In this problem, you will see how Tintin, a five year'sold boy, creates trouble for his parents. Tintin is a joyful boy and is alwaysbusy in doing something. But what he does is no

递推+高精度 UVA 10497 Sweet Child Makes Trouble(可爱的孩子惹麻烦)

题目链接 题意: n个物品全部乱序排列(都不在原来的位置)的方案数. 思路: dp[i]表示i个物品都乱序排序的方案数,所以状态转移方程.考虑i-1个物品乱序,放入第i个物品一定要和i-1个的其中一个交换位置,即:考虑i-2个物品乱序,第i-1个和第i个首先在原来的位置,两种方法使得乱序,一种和第i个交换(不能和前i-2个交换,那样成dp[i-1]),还有一种是第i个先和第i-1个交换,再和前i-2个其中一个交换,即,仔细想想,这个和dp[i-1]是不同的交换方法. 另外: 还有二维的dp写法,

UVA-10497 Sweet Child Makes Trouble (计数+高精度)

题目大意:这是一道简单排列组合题 .简单说下题意:n件物品,把这n件物品放到不是原来的位置,问所有的方案数.所有的位置都没有变. 题目解析:按照高中的方法,很快得到一个递推公式:f [n]= (n-1)*( f [n-1] + f [n-2] ) .这个公式也不难理解,可以采取这样的策咯:一件物品一件物品的放,则第一件物品,假设编号1,有n-1个位置可放,假如放到原来物品 2 的位置,则再放物品 2,依次进行下去......也就是放到的位置上原来是哪个物品则下一个就放该物品 .按照这种策咯,放第

UVA 12105 - Bigger is Better(DP+高精度)

题目链接:12105 - Bigger is Better 题意:一些火柴,问你能组成整除m最大的数字是多少. 思路:dp[i][j]表示用i根火柴,组成%m余数为j的最大数字,末尾多一个数字k的状态就是dp[i + num[k]][(j * 10 + k) % m],由于最多可能50位数,所以要用高精度. 注意一个优化点,由于高精度的计算上只需要乘10+k,常规的高精度乘法复杂度还是有点高会超时,所以用数组去模拟,每次*10 + k的时候就往后多一位即可. 代码: #include <stdi

uva 11584 Partitioning by Palindromes 线性dp

// uva 11584 Partitioning by Palindromes 线性dp // // 题目意思是将一个字符串划分成尽量少的回文串 // // f[i]表示前i个字符能化成最少的回文串的数目 // // f[i] = min(f[i],f[j-1] + 1(j到i是回文串)) // // 这道题还是挺简单的,继续练 #include <algorithm> #include <bitset> #include <cassert> #include <

UVA - 825Walking on the Safe Side(dp)

题目: UVA - 825Walking on the Safe Side(dp) 题目大意:给出一个n * m的矩阵,起点是1 * 1,终点是n * m,这个矩阵上有些点是不可以经过的,要求从起点到终点距离最短,并且不能走那种不能走的点,一共有多少种方式. 解题思路:要求路径最短的话,每个点要不向右走,要不向下走.dp[i][j] = dp[i][j + 1] + dp[i + 1][j]:当这个点不能通过,dp[i][j] = 0:这个坑点在样例输入,不一定是规范的输入,可能两个数字之间很多

poj 1625 Censored!(AC自动机+DP+高精度)

题目链接:poj 1625 Censored! 题目大意:给定N,M,K,然后给定一个N字符的字符集和,现在要用这些字符组成一个长度为M的字符串,要求不包 括K个子字符串. 解题思路:AC自动机+DP+高精度.这题恶心的要死,给定的不能匹配字符串里面有负数的字符情况,也算是涨姿势 了,对应每个字符固定偏移128单位. #include <cstdio> #include <cstring> #include <queue> #include <vector>

【bzoj2764】[JLOI2011]基因补全 dp+高精度

题目描述 在生物课中我们学过,碱基组成了DNA(脱氧核糖核酸),他们分别可以用大写字母A,C,T,G表示,其中A总与T配对,C总与G配对.两个碱基序列能相互匹配,当且仅当它们等长,并且任意相同位置的碱基都是能相互配对的.例如ACGTC能且仅能与TGCAG配对.一个相对短的碱基序列能通过往该序列中任意位置补足碱基来与一个相对长的碱基序列配对.补全碱基的位置.数量不同,都将视为不同的补全方案.现在有两串碱基序列S和T,分别有n和m个碱基(n>=m),问一共有多少种补全方案. 输入 数据包括三行. 第