递推+高精度 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写法,虽然高精度开不了,但是还是有启发意义。设dp[i][j]表示i个物品j个乱序的方案数,状态转移方程,最后一项的(i-j+1)的意思是从前i-1个中选择在原来位置的物品进行交换,即

#include <bits/stdc++.h>

const int MAXN = 2000 + 5;
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);
};

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) == 1 && n != -1) {
        dp[n].Put ();
        puts ("");
    }
    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;
}

  

时间: 2024-08-08 21:00:53

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

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 -

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 10254 The Priest Mathematician

题目传送门 1 /* 2 题意:汉诺塔问题变形,多了第四个盘子可以放前k个塔,然后n-k个是经典的汉诺塔问题,问最少操作次数 3 递推+高精度+找规律:f[k]表示前k放在第四个盘子,g[n-k]表示经典三个盘子,2 ^ (n - k) - 1 4 所以f[n] = min (f[k] * 2 + g[n-k]),n<=10000,所要要用高精度,另外打表能看出规律 5 */ 6 /************************************************ 7 * Auth

递推 + 高精度 --- Tiling

Tiling Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7264   Accepted: 3528 Description In how many ways can you tile a 2xn rectangle by 2x1 or 2x2 tiles? Here is a sample tiling of a 2x17 rectangle. Input Input is a sequence of lines,

POJ 2506 Tiling (递推+高精度)

[题目链接]click here~~ [题目大意] In how many ways can you tile a 2xn rectangle by 2x1 or 2x2 tiles? Here is a sample tiling of a 2x17 rectangle. [解题思路]: (1)一个2*2的格子有三种填充方法: 两个横着放, 两个竖着放, 放一个2*2 (2)得出递推公式F[i]=F[i-1]+F[i-2]*2 然后就是套高精度模板了 代码; /* Author:HRW 递推+

BZOJ 1089 严格n元树 (递推+高精度)

题解:用a[i]表<=i时有几种树满足度数要求,那么这样就可以递归了,a[i]=a[i-1]^n+1.n个节点每个有a[i-1]种情况,那么将其相乘,最后加上1,因为深度为0也算一种.那么答案就是a[n]-a[n-1].然后就是高精度的问题了,发现很久没有现码高精度没手感了,连高进度加法进位都出了些问题,需要特别注意. #include <cstdio> #include <cstring> #include <algorithm> using namespace

[luogu]P1066 2^k进制数[数学][递推][高精度]

[luogu]P1066 2^k进制数 题目描述 设r是个2^k 进制数,并满足以下条件: (1)r至少是个2位的2^k 进制数. (2)作为2^k 进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进制数q后,则q的总位数不超过w. 在这里,正整数k(1≤k≤9)和w(k<W≤30000)是事先给定的. 问:满足上述条件的不同的r共有多少个? 我们再从另一角度作些解释:设S是长度为w 的01字符串(即字符串S由w个“0”或“1”组成),S对应于上述条件(3)中的q

[BZOJ1089][SCOI2003]严格n元树(递推+高精度)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1089 分析: 第一感觉可以用一个通式求出来,但是考虑一下很麻烦,不好搞的.很容易发现最底层必有一个是满高度的,其他的任意. 所以直接的递推也不好想. (以下所述都是n元树) 于是可以令f[d]为深度<=d的树的个数,那么深度为d的就是f[d]-f[d-1] 对于深度<=d的又该怎么处理呢? 考虑第一层的n个点(根为0层),每个点都要底下连子树,深度为0~i-1,方案数即f[d-1]