1到N,N个数的排列,求解任意两连续数字不相邻的方案数

题目来源:

264:阿岳真的很严格

大致题意:

输入n

从1到n 共n个数 在所有的排列中 任意两个连续的数字不相邻的排列有多少种

例如:

输入n等于4时  输出2 有两种

分别是3 1 4 2和2 4 1 3 都是满足要求的合法排列

其他排列都不符合要求 例如1 4 2 3中2和3连续 不合法

解法1:O(N)的一维DP

用n表示输入 用f【n】表示对应的输出

1-5的f【n】用DFS暴力跑 之后的DP 

状态转移方程:

f[i] = (i + 1) * f[i - 1] - (i - 2) * f[i - 2] - (i - 5) * f[i - 3] + (i - 3) * f[i - 4];

f【n】即为答案

解法2:O(N*N)的二维DP

f[0/1][i][j]:0/1表示i和i-1这两个数是否连续 i表示1到i i个数的情况 j表示在i个数中有j对数连续的情况

即,i和i-1 不连续/连续 一共i个数 其中有j对数连续的方案数是f【0/1】【i】【j】

i为1-5的所有情况DFS暴力跑 之后二维DP

状态转移方程:

f[0][i][j] = f[0][i - 1][j + 1] * (j + 1) + f[1][i - 1][j + 1] * j + f[0][i - 1][j] * (i - j - 2) + f[1][i - 1][j] * (i - j - 1);

f[1][i][j] = f[1][i - 1][j - 1] + f[1][i - 1][j] + f[0][i - 1][j - 1] * 2;

f【0】【n】【0】即为答案

UPD1:

解法2可以把f[0][1][0]设为1 其他设为0 直接从2开始遍历DP 不需要DFS跑前几个

AC代码1:

// #define NDEBUG
#include <bits/stdc++.h>
using namespace std;
namespace AIN
{
	using db = double;
	using ll = long long;
#define edl '\n'
#define str string
#define pll pair<ll, ll>
#define fir first
#define sec second
#define heap priority_queue
#define SPO(n) fixed << setprecision(n)
#define FOR(i, l, r) for (auto i = l; i <= (r); ++i)
#define ROF(i, r, l) for (auto i = r; i >= (l); --i)
#ifdef debugcmd
#define DBG(n) cout << "!!! " << #n << ": " << n << edl
#else
#define DBG(n) ;
#endif
	template <typename T>
	T KSM(T base, long long exp)
	{
		// assert(exp >= 0);
		T res = 1;
		while (exp)
		{
			if (exp & 1)
				res *= base;
			base *= base;
			exp >>= 1;
		}
		return res;
	}
	long long __lcm(long long lhs, long long rhs) { return lhs / __gcd(lhs, rhs) * rhs; }
	// constexpr db PI = acos(-1.0);
	// constexpr db EPS = 1.0e-9;
	constexpr long long LNF = 0x3f3f3f3f3f3f3f3fLL;
	constexpr int INF = 0x3f3f3f3f;
	// constexpr long long MOD = 998244353;
	// constexpr long long MOD = 1e9 + 7;
	constexpr long long MOD = 7777777;
	constexpr int MXN = 1e5 + 5;
}
using namespace AIN;
template <long long P>
struct ModInt
{
public:
	ModInt() : _v(0) {}
	template <typename T>
	ModInt(T v) { _v = ((long long)v % P + P) % P; }
	long long val() const { return _v; }
	ModInt &operator++()
	{
		++_v;
		if (_v == P)
			_v = 0;
		return *this;
	}
	ModInt &operator--()
	{
		if (_v == 0)
			_v = P;
		--_v;
		return *this;
	}
	ModInt operator++(int)
	{
		ModInt oldVal = *this;
		++*this;
		return oldVal;
	}
	ModInt operator--(int)
	{
		ModInt oldVal = *this;
		--*this;
		return oldVal;
	}
	ModInt &operator+=(const ModInt &rhs)
	{
		_v += rhs._v;
		_v %= P;
		return *this;
	}
	ModInt &operator-=(const ModInt &rhs)
	{
		_v -= rhs._v;
		_v = (_v + P) % P;
		return *this;
	}
	ModInt &operator*=(const ModInt &rhs)
	{
		_v *= rhs._v;
		_v %= P;
		return *this;
	}
	ModInt &operator/=(const ModInt &rhs) { return *this = *this * rhs.inv(); }
	ModInt operator+() const { return *this; }
	ModInt operator-() const { return ModInt() - *this; }
	ModInt pow(long long exp) const
	{
		// assert(exp>=0);
		ModInt res = 1;
		ModInt base = *this;
		while (exp)
		{
			if (exp & 1)
				res *= base;
			base *= base;
			exp >>= 1;
		}
		return res;
	}
	ModInt inv() const
	{
		// assert(_v);
		return pow(P - 2);
	}
	friend ModInt operator+(const ModInt &lhs, const ModInt &rhs)
	{
		ModInt res = lhs;
		res += rhs;
		return res;
	}
	friend ModInt operator-(const ModInt &lhs, const ModInt &rhs)
	{
		ModInt res = lhs;
		res -= rhs;
		return res;
	}
	friend ModInt operator*(const ModInt &lhs, const ModInt &rhs)
	{
		ModInt res = lhs;
		res *= rhs;
		return res;
	}
	friend ModInt operator/(const ModInt &lhs, const ModInt &rhs)
	{
		ModInt res = lhs;
		res /= rhs;
		return res;
	}
	friend bool operator==(const ModInt &lhs, const ModInt &rhs) { return lhs._v == rhs._v; }
	friend bool operator!=(const ModInt &lhs, const ModInt &rhs) { return lhs._v != rhs._v; }
	friend std::istream &operator>>(std::istream &is, ModInt &aim)
	{
		long long tmp;
		is >> tmp;
		aim = ModInt(tmp);
		return is;
	}
	friend std::ostream &operator<<(std::ostream &os, const ModInt &aim) { return os << aim.val(); }

private:
	long long _v;
};
using mint = ModInt<MOD>;

ll n;
mint f[MXN];

void Init(void)
{
	f[1] = 1;
	f[2] = 0;
	f[3] = 0;
	f[4] = 2;
	f[5] = 14;
	FOR(i, 6, 1e3 + 5)
	f[i] = (i + 1) * f[i - 1] - (i - 2) * f[i - 2] - (i - 5) * f[i - 3] + (i - 3) * f[i - 4];
	return;
}
void Solve(void)
{
	cout << f[n] << edl;
	return;
}
int main(void)
{
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	// #ifdef cincoutcmd
	// freopen("cin.txt","r",stdin);
	// freopen("cout.txt","w",stdout);
	// #endif
	Init();
	while (cin >> n)
		Solve();
	return 0;
}

AC代码2:

// #define NDEBUG
#include <bits/stdc++.h>
using namespace std;
namespace AIN
{
	using db = double;
	using ll = long long;
#define edl '\n'
#define str string
#define pll pair<ll, ll>
#define fir first
#define sec second
#define heap priority_queue
#define SPO(n) fixed << setprecision(n)
#define FOR(i, l, r) for (auto i = l; i <= (r); ++i)
#define ROF(i, r, l) for (auto i = r; i >= (l); --i)
#ifdef debugcmd
#define DBG(n) cout << "!!! " << #n << ": " << n << edl
#else
#define DBG(n) ;
#endif
	template <typename T>
	T KSM(T base, long long exp)
	{
		// assert(exp >= 0);
		T res = 1;
		while (exp)
		{
			if (exp & 1)
				res *= base;
			base *= base;
			exp >>= 1;
		}
		return res;
	}
	long long __lcm(long long lhs, long long rhs) { return lhs / __gcd(lhs, rhs) * rhs; }
	// constexpr db PI = acos(-1.0);
	// constexpr db EPS = 1.0e-9;
	constexpr long long LNF = 0x3f3f3f3f3f3f3f3fLL;
	constexpr int INF = 0x3f3f3f3f;
	// constexpr long long MOD = 998244353;
	// constexpr long long MOD = 1e9 + 7;
	constexpr long long MOD = 7777777;
	constexpr int MXN = 1e3 + 5;
}
using namespace AIN;
template <long long P>
struct ModInt
{
public:
	ModInt() : _v(0) {}
	template <typename T>
	ModInt(T v) { _v = ((long long)v % P + P) % P; }
	long long val() const { return _v; }
	ModInt &operator++()
	{
		++_v;
		if (_v == P)
			_v = 0;
		return *this;
	}
	ModInt &operator--()
	{
		if (_v == 0)
			_v = P;
		--_v;
		return *this;
	}
	ModInt operator++(int)
	{
		ModInt oldVal = *this;
		++*this;
		return oldVal;
	}
	ModInt operator--(int)
	{
		ModInt oldVal = *this;
		--*this;
		return oldVal;
	}
	ModInt &operator+=(const ModInt &rhs)
	{
		_v += rhs._v;
		_v %= P;
		return *this;
	}
	ModInt &operator-=(const ModInt &rhs)
	{
		_v -= rhs._v;
		_v = (_v + P) % P;
		return *this;
	}
	ModInt &operator*=(const ModInt &rhs)
	{
		_v *= rhs._v;
		_v %= P;
		return *this;
	}
	ModInt &operator/=(const ModInt &rhs) { return *this = *this * rhs.inv(); }
	ModInt operator+() const { return *this; }
	ModInt operator-() const { return ModInt() - *this; }
	ModInt pow(long long exp) const
	{
		// assert(exp>=0);
		ModInt res = 1;
		ModInt base = *this;
		while (exp)
		{
			if (exp & 1)
				res *= base;
			base *= base;
			exp >>= 1;
		}
		return res;
	}
	ModInt inv() const
	{
		// assert(_v);
		return pow(P - 2);
	}
	friend ModInt operator+(const ModInt &lhs, const ModInt &rhs)
	{
		ModInt res = lhs;
		res += rhs;
		return res;
	}
	friend ModInt operator-(const ModInt &lhs, const ModInt &rhs)
	{
		ModInt res = lhs;
		res -= rhs;
		return res;
	}
	friend ModInt operator*(const ModInt &lhs, const ModInt &rhs)
	{
		ModInt res = lhs;
		res *= rhs;
		return res;
	}
	friend ModInt operator/(const ModInt &lhs, const ModInt &rhs)
	{
		ModInt res = lhs;
		res /= rhs;
		return res;
	}
	friend bool operator==(const ModInt &lhs, const ModInt &rhs) { return lhs._v == rhs._v; }
	friend bool operator!=(const ModInt &lhs, const ModInt &rhs) { return lhs._v != rhs._v; }
	friend std::istream &operator>>(std::istream &is, ModInt &aim)
	{
		long long tmp;
		is >> tmp;
		aim = ModInt(tmp);
		return is;
	}
	friend std::ostream &operator<<(std::ostream &os, const ModInt &aim) { return os << aim.val(); }

private:
	long long _v;
};
using mint = ModInt<MOD>;

const ll LIM = 1e3 + 3;
ll n;
mint f[2][MXN][MXN];
bool vis[MXN];
ll v[MXN];
ll p[MXN];

void Init(ll n)
{
	FOR(i, 1, n)
	vis[i] = false;
	v[0] = -1;
	p[0] = -1;
	return;
}
void DFS(ll pos, ll num, ll len)
{
	if (pos == len)
	{
		ll flag = 0;
		if (p[len] == p[len - 1] + 1 || p[len] == p[len - 1] - 1)
			flag = 1;
		ll cnt = 0;
		FOR(i, 1, len - 1)
		if (v[i] == v[i + 1] + 1 || v[i] == v[i + 1] - 1)
			++cnt;
		++f[flag][len][cnt];
		return;
	}
	FOR(i, 1, len)
	{
		if (!vis[i])
		{
			vis[i] = true;
			v[pos + 1] = i;
			p[i] = pos + 1;
			DFS(pos + 1, i, len);
			vis[i] = false;
		}
	}
	return;
}
void Pre(void)
{
	FOR(i, 1, 5)
	{
		Init(i);
		DFS(0, -1, i);
	}
	FOR(i, 6, LIM)
	FOR(j, 0, i - 1)
	{
		f[0][i][j] = f[0][i - 1][j + 1] * (j + 1) + f[1][i - 1][j + 1] * j + f[0][i - 1][j] * (i - j - 2) + f[1][i - 1][j] * (i - j - 1);
		f[1][i][j] = f[1][i - 1][j - 1] + f[1][i - 1][j] + f[0][i - 1][j - 1] * 2;
	}
	return;
}
void Solve(void)
{
	cout << f[0][n][0] << edl;
	return;
}
int main(void)
{
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	// #ifdef cincoutcmd
	// freopen("cin.txt","r",stdin);
	// freopen("cout.txt","w",stdout);
	// #endif
	Pre();
	while (cin >> n)
		Solve();
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值