Loading

CF1338E JYPnation

因为是竞赛图,所以缩点之后得到的一定是一条沿着拓扑序的有向链 \(S_1,S_2,\cdots,S_k\),并且 \(S_i\to S_j\) 之间有边当且仅当 \(i<j\)

然后考虑如何利用题目给的特殊性质,首先有一个结论就是若一个 \(n\) 阶竞赛图 \(G\) 是强连通的,则 \(\forall k\in[3,n]\)\(G\) 中存在长度为 \(k\) 的圈,证明:

先证明 \(G\) 中存在长度为 \(n\) 的圈(即哈密顿回路):

考虑数学归纳法。

对于所有的 \(u\in G\),如果 \(G'=G\backslash\{u\}\) 为强连通,则 \(G'\) 中存在长为 \(n-1\) 的圈。然后将 \(u\) 放回 \(G'\),由于强连通性可以得到 \(G\) 中有长为 \(n\) 的圈。

\(G'\) 非强连通,则由归纳假设,所有 \(S_i\) 都有哈密顿回路,由强连通性,\(S_1\) 中存在点 \(x\) 满足 \(u\to x\),且 \(S_k\) 中存在点 \(y\) 满足 \(y\to u\)。这样就存在一条 \(x\to \ldots \to y\to u\to x\) 的哈密顿回路。

然后考虑证明 \(G\) 中存在长为 \(n-1\) 的圈:

类似地,若 \(G'\) 为强连通,则已经存在长为 \(n-1\) 的圈。

否则,就有 \(k\ge 3\) 或存在 \(|S_i|\ge 3\),类似上面一样构造即可。

因此结论成立,同时可以发现在此题中 \(|S_i|=1,i\in [1,k-1]\)

证明:若 \(|S_i|>1\),则 \(|S_i|\ge 3\),随便再取一个点就可以发现这不满足特殊性质。

因此,若两个点 \(u,v\) 中有一个点不在 \(S_k\) 中,则这两个点就一定在不同的连通分量,因此两个点一定不能互相到达,贡献分别为 \(1\)\(+\infty\)。总贡献为:

\[\frac{(n-|S_k|)(n+|S_k|-1)(1+614n)}{2} \]

接下来就只需要考虑剩下的 \(G\) 连通的情况,首先可以发现任意两点距离 \(\le 3\)

证明:

假设存在 \(u,v\) 满足 \(\text{dis}(u,v)=k\),最短路为 \(u\to a_1\to a_2\to \ldots \to a_{k-2}\to a_{k-1}\to v\)

因此存在边 \(v\to u,v\to a_{k-2},a_1\to u,a_2\to u\),然后就会发现这与特殊性质矛盾了。

然后问题就转化成找分别有多少点对距离为 \(1/2/3\),假设他们分别为 \(d_1,d_2,d_3\)

可以发现 \(d_1=\binom n 2\),因此 \(d_2+d_3=\binom n 2\)

\(\text{dis}(u,v)=2\) 当且仅当 \(v\to u\) 且存在一个点 \(a\) 满足 \(u\to a,a\to v\)

但是直接暴力判断是 \(\mathcal O(n^3)\) 或者 \(\mathcal O(n^2\log n)\) 的,并不能过这道题。

继续考虑题目性质:

假设存在另一个点 \(b\) 满足存在 \(u\to b,a\to b\),则有 \(b\to v\),即 \(b\) 也是可以使 \(\text{dis}(u,v)=2\) 的点。(否则又会与特殊性质矛盾)

因此假设 \(u\) 出边指向的点的集合为 \(S\),则不管导出子图 \(G[S]\) 是否强连通,都可以取到拓扑序最靠后的强连通分量(设为 \(T\))的任意一点,因此 \(S\) 中的任意一点都可以仅通过它们之间的连边到达 \(T\)。因此只要 \(S\) 中存在满足条件的 \(a\)\(T\) 一定满足。

而这个 \(T\) 只和 \(u\) 有关,因此可以在 \(\mathcal O(n^2)\) 得到所有点的 \(T\)

总时间复杂度 \(\mathcal O(n^2)\)

#include<bits/stdc++.h>
#define R(i,a,b) for(int i=(a),i##E=(b);i<=i##E;i++)
#define L(i,a,b) for(int i=(b),i##E=(a);i>=i##E;i--)
using namespace std;
inline int trans(char x)
{
	if(isdigit(x)) return x-'0';
	if(isalpha(x)) return x-'A'+10;
	return -1;
}
bool e[8888][8888];
int n,dfn[8888],low[8888],stk[8888],top;
int bel[8888],siz[8888],to[8888];
int cnt,tim;
void tarjan(int u)
{
	dfn[u]=low[u]=++tim;
	stk[++top]=u;
	R(v,1,n) if(e[u][v])
	{
		if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
		else low[u]=min(low[u],dfn[v]);
	}
	if(low[u]==dfn[u])
	{
		++cnt;
		int x;
		do 
		{
			x=stk[top--];
			bel[x]=cnt;
			++siz[cnt];
		}while(x^u);
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n;
	R(i,1,n)
	{
		string s;
		cin>>s;
		for(int j=1,k=0;j<=n;j+=4,k++)
		{
			int d=trans(s[k]);
			e[i][j]=d&8,e[i][j+1]=d&4,e[i][j+2]=d&2,e[i][j+3]=d&1;
		}
	}
	R(i,1,n) if(!dfn[i]) tarjan(i);
	R(i,1,n) R(j,1,n) if(bel[i]==1&&e[i][j]&&(!to[i]||e[to[i]][j])) to[i]=j;
	int d1=siz[1]*(siz[1]-1)/2,d2=0,d3;
	R(i,1,n) R(j,1,n) if(bel[i]==1&&bel[j]==1&&e[j][i]&&e[to[i]][j]) ++d2;
	d3=d1-d2;
	//cout<<d1<<" "<<d2<<" "<<d3<<endl;
	cout<<1ll*(n-siz[1])*(n+siz[1]-1)/2*(n*614+1)+d1+2ll*d2+3ll*d3<<endl;
}
posted @ 2022-03-19 00:20  yoisaki_hizeci  阅读(27)  评论(0)    收藏  举报