首页 > 其他分享 >CodeForces 1466H Finding satisfactory solutions

CodeForces 1466H Finding satisfactory solutions

时间:2024-01-18 17:56:28浏览次数:39  
标签:satisfactory vc int 1466H ++ vector maxn Finding now

洛谷传送门

CF 传送门

考虑给定 \(b\) 如何构造 \(a\)。

拎出基环树的环部分,把这些点连同它们的边删掉(这个环一定在答案中)。递归做即可。

考虑我们在 \(a\) 的环上连一些在 \(\{b_{i, n}\}\) 中排得比 \(a_i\) 前的 \(i \to j\)。可以将问题转化为,若干个环,缩点后连一些边使得它成为 DAG。

一个 DAG 对应的 \(b\) 的个数就是 \(\prod\limits_{i = 1}^n d_i! (n - d_i - 1)!\),因为入边和出边在 \(b_i\) 中可以独立地随意排列。

然后考虑经典状压 dp,设 \(f(S)\) 为点集 \(S\) 形成了一个 DAG(缩点之后),对应的 \(b\) 的个数。转移枚举入度为 \(0\) 的集合 \(T\),乘上一个容斥系数 \((-1)^{|T| + 1}\),可得:

\[f(S) = \sum\limits_{T \subseteq S \land T \ne \varnothing} f(S \setminus T) (-1)^{|T| + 1} g(sz_T, sz_S - sz_T) \]

其中 \(sz_S\) 为环集 \(S\) 的点数。\(g(n, m)\) 为 \(n\) 个点可能连向 \(m\) 个点,那 \(n\) 个点的 \(\prod\limits_{i = 1}^n d_i! (n - d_i - 1)!\) 之和。容易发现这 \(n\) 个点互相独立,于是考虑设 \(h(m)\) 为一个点可能连向 \(m\) 个点的系数。有:

\[h(m) = \sum\limits_{i = 0}^m \binom{m}{i} i! (n - 1 - i)! \]

\[g(n, m) = h(m)^n \]

设环数为 \(c\),那么此时的复杂度为 \(O(3^c)\),不能通过。注意到因为转移系数只和 \(S, T\) 的大小和点数有关,于是考虑把 \(\{p_c\}\) 压缩进状态,其中 \(p_c\) 为长度为 \(c\) 的环的出现次数。这样 \(n = 40\) 时状态数最大为 \(1440\),总时间复杂度 \(O(1440^2 c)\),可以通过。

code
// Problem: H. Finding satisfactory solutions
// Contest: Codeforces - Good Bye 2020
// URL: https://codeforces.com/problemset/problem/1466/H
// Memory Limit: 1024 MB
// Time Limit: 5000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 45;
const ll mod = 1000000007;

ll n, a[maxn], g[maxn][maxn], fac[maxn], C[maxn][maxn], m, f[1444];
pii c[maxn];
bool vis[maxn];

inline vector<int> dec(int x) {
	vector<int> vc(m);
	for (int i = 0; i < m; ++i) {
		vc[i] = x % (c[i].scd + 1);
		x /= (c[i].scd + 1);
	}
	return vc;
}

inline int enc(vector<int> vc) {
	int x = 0;
	for (int i = m - 1; ~i; --i) {
		x = x * (c[i].scd + 1) + vc[i];
	}
	return x;
}

inline vector<int> nxt(vector<int> now, vector<int> vc) {
	vector<int> nv = vc;
	++nv[0];
	for (int i = 0; i < m; ++i) {
		if (nv[i] > now[i]) {
			nv[i] = 0;
			++nv[i + 1];
		} else {
			break;
		}
	}
	return nv;
}

void solve() {
	scanf("%lld", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i]);
	}
	fac[0] = 1;
	for (int i = 1; i <= n; ++i) {
		fac[i] = fac[i - 1] * i % mod;
	}
	for (int i = 0; i <= n; ++i) {
		C[i][0] = C[i][i] = 1;
		for (int j = 1; j < i; ++j) {
			C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
		}
	}
	for (int i = 0; i < n; ++i) {
		ll k = 0;
		for (int j = 0; j <= i; ++j) {
			k = (k + C[i][j] * fac[j] % mod * fac[n - j - 1]) % mod;
		}
		g[0][i] = 1;
		for (int j = 1; j <= n; ++j) {
			g[j][i] = g[j - 1][i] * k % mod;
		}
	}
	vector<int> cir;
	for (int i = 1; i <= n; ++i) {
		if (vis[i]) {
			continue;
		}
		int u = i, cnt = 0;
		do {
			vis[u] = 1;
			u = a[u];
			++cnt;
		} while (u != i);
		cir.pb(cnt);
	}
	sort(cir.begin(), cir.end());
	int len = (int)cir.size();
	for (int i = 0, j = 0; i < len; i = (++j)) {
		while (j + 1 < len && cir[j + 1] == cir[i]) {
			++j;
		}
		c[m++] = mkp(cir[i], j - i + 1);
	}
	int all = 1;
	for (int i = 0; i < m; ++i) {
		all *= (c[i].scd + 1);
	}
	f[0] = 1;
	for (int i = 1; i < all; ++i) {
		vector<int> now = dec(i), p(m);
		int s0 = 0, c0 = 0;
		for (int j = 0; j < m; ++j) {
			s0 += now[j] * c[j].fst;
			c0 += now[j];
		}
		while (1) {
			int _j = enc(p), s1 = 0, c1 = 0;
			if (_j == i) {
				break;
			}
			for (int k = 0; k < m; ++k) {
				s1 += (now[k] - p[k]) * c[k].fst;
				c1 += now[k] - p[k];
			}
			ll coef = 1;
			for (int k = 0; k < m; ++k) {
				coef = coef * C[now[k]][p[k]] % mod;
			}
			f[i] = (f[i] + f[_j] * ((c1 & 1) ? 1 : mod - 1) % mod * g[s1][s0 - s1] % mod * coef) % mod;
			p = nxt(now, p);
		}
	}
	printf("%lld\n", f[all - 1]);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:satisfactory,vc,int,1466H,++,vector,maxn,Finding,now
From: https://www.cnblogs.com/zltzlt-blog/p/17973095

相关文章

  • Cloth Simulation with Root Finding and Optimization
    目录0前言1ImplicitMethod1.1Root-finding1.2Optimization1.3Insight2Newton-RaphsonMethod3Mass-SpringSystem3.1Matrixcalculus3.2ASpringwithTwoEnds4ExplainationofInitCodewith3DImage4.1Initialize4.2Index4.3Edge4.4SortEdge5Update6Get_G......
  • RTS核心技术:流场寻路详解(Flow Field Pathfinding)
    RTS里面经常会有很多角色,群体一起寻路到目的地附近,这种寻路是如何实现的,今天给大家详细的讲解基于流场寻路的算法。在本教程中,我将解释向量场寻路及其相对于Dijkstra等传统寻路算法的优势。对Dijkstra算法和势场的基本理解将有助于理解本文,但不是必需的。寻路的问题有很多种解决......
  • 一种解决A*Pathfindings使用RichAI寻路 跌落出导航网格的方法
    A*Pathfinding是Unity中一个比较常用的寻路插件,其主要功能是绘制导航图并让物体沿着导航图向目标移动,可结合多种方法进行寻路方式的扩展。 该插件付费的Pro版拥有一个通过投影方式获得场景中所有网格(mesh),在网格(mesh)标面自动生成导航网格的功能,称为RecastGraph,同时配合用于A......
  • Go - Finding the Shortest Path on a Graph
    Problem: Youwanttofindtheshortestpathbetweentwonodesonaweightedgraph.Solution: UseDijkstra’salgorithmtofindtheshortestpathbetweentwonodes.Dijkstra’salgorithmalsousesapriorityqueue,whichcanbeimplementedusingaminheap.......
  • 5、题目:Training in Creative Problem Solving: Effects on Ideation and Problem Fin
    期刊信息(1)作者:GeorgeB.Graen,StephenG.Graen(2)期刊:OrganizationalBehaviorandHumanPerformance(3)DOI:10.1016/0030-5073(82)90233-1(4)ISSN:0030-5073   研究背景创造力训练作为工业培训的一个子集,普遍面临着工业培训研究的许多问题,也面临着一些独特的问题。......
  • Re: finding all cycles in a graph
    ref:https://cs.stackexchange.com/questions/7216/find-the-simple-cycles-in-a-directed-graphRe:findingallcyclesinagraphFrom: JuanPabloCarbajalSubject: Re:findingallcyclesinagraphDate: Wed,25Jan201219:43:48+0100OnWed,Jan25,2012a......
  • Codeforces 1444E - Finding the Vertex
    非常神秘的一道题,当之无愧的*3500。首先考虑转化题意。考虑一种决策树,由于我们每次问一条边之后,相当于会根据信息删掉两个连通块中的一个,因此一种决策树实际上对应了原树的一棵边分树。而为了让最坏情况下的询问次数最少,我们目标实际上是最小化边分树的深度。考虑借鉴P5912JA......
  • Information Gathering - SubDomains Finding
    SubDomainsFindingByOnlineWebsiteshttps://crt.sh/crt.sh通过证书记录查询子域名,%为通配符ByOpensourceToolssublist3r安装在kali中使用aptinstallsublist3r即可安装,或在githubhttps://github.com/aboul3la/Sublist3r下载运行apt安装直接输入sublist3r......
  • MongDb 报错 Finding the split vector for
    "Findingthesplitvectorfor"是MongoDB中分片操作时出现的错误消息,提示系统正在尝试为特定集合查找分片的分割点(splitvector),但该操作过程中出现了异常。该错误可能......
  • [LeetCode] 1817. Finding the Users Active Minutes
    Youaregiventhelogsforusers'actionsonLeetCode,andaninteger k.Thelogsarerepresentedbya2Dintegerarray logs whereeach logs[i]=[IDi,tim......