[硫化铂]小G的连通图

小G的连通图

题目概述

在这里插入图片描述
在这里插入图片描述

题解

首先,我们将原题目中的连边解析一下,在不互质的两个数间连边,也就是说这两个点间是由公因数的。
我们转化一下,我们将每条边都从 k p kp kp连到 ( k + 1 ) p (k+1)p (k+1)p,显然原图中的每条边都可以转化成现在图上的一条路径,其连通性是与原图等价的。
由于不同质数间实际上是独立的,所以相当于每个质数都可以在这 n n n个点中选择一个点,充当起点,然后按照 p p p的等距离连边。显然,无论怎么选择这些点,我们都可以通过 CRT 构造出一组合法解。
那么这道题就被我们转化成了一个构造题。

假设我们的 n = N + 1 n=N+1 n=N+1,我们需要构造的区间为 [ x , x + N ] [x,x+N] [x,x+N]
如果我们把所有质数的起点都放在点 x x x上的话,显然,只有 x + 1 x+1 x+1没有被连到。
假设,我们现在选择一个 a ∈ ( n , N ] a\in(\sqrt{n},N] a(n ,N],由于除了 x + a x+a x+a之外的原先被 x x x通过 a a a连到的点都可以被通过其它的质数连到,所以此时独立的只有 x + a x+a x+a
对于 x + 1 x+1 x+1,我们将 a a a放到它上面,它自己连向了 x + a + 1 x+a+1 x+a+1,而 x + a + 1 x+a+1 x+a+1本身是与 x x x联通的,现在我们的 x x x就与 x + a + 1 x+a+1 x+a+1联通了。
之后我们发现,我这样的连法可以使得 x + 2 a + 1 x+2a+1 x+2a+1也与 x x x联通,那么 x + 2 a + 1 x+2a+1 x+2a+1就可以空出来一个 2 a + 1 2a+1 2a+1,因为在这张图中,原先通过 2 a + 1 2a+1 2a+1 x x x联通的点,都有着其它方式与 x x x联通。
那么我们就可以让 x + a x+a x+a拥有这个 2 a + 1 2a+1 2a+1,他会连向 x + 3 a + 1 x+3a+1 x+3a+1,与 x x x联通。
所以只要我们存在一个大于 n \sqrt{n} n 的质数 p p p使得 2 p + 1 2p+1 2p+1为质数并且 3 p + 2 ⩽ n 3p+2\leqslant n 3p+2n,那么我们就能构造出一组解。
具体构造方法就是通过CRT找到模除 p p p 2 p + 1 2p+1 2p+1之外的质数都为 0 0 0且,模 p p p 1 1 1,模 2 p + 1 2p+1 2p+1 p p p的数就行了。
可以发现,当 n ⩾ 35 n\geqslant 35 n35时,我们都可以通过上面的方法找出一组解,而当 n < 35 n< 35 n<35时,我们完全可以都过暴力找出解嘛。

由于我们的 n n n比较大,答案也比较大,所以需要打高精度。
复杂度大概是 O ( n ⋅ 高 精 ) O\left(n\cdot 高精\right) O(n)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int mod=1e5+3;
const int inv2=499122177;
const int jzm=2333;
const int lim=10000000;
const int zero=2000;
const int n1=2000;
const int orG=3,ivG=332748118;
const long double Pi=acos(-1.0);
const double eps=1e-12;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,a,prime[MAXN],cntp;
bool oula[MAXN];
int ans[18]={2184,27829,27828,87890,87890,171054,171054,323510,127374,323510,151062,151062,151062,151061,151060,151059,151058,7106718};
struct BigInt{
	int a[MAXN],len;BigInt(){len=0;}
	BigInt(int X){len=0;while(X)a[++len]=X%lim,X/=lim;}
	BigInt operator * (const int &rhs)const{
		BigInt res;int x=0;res.len=len;
		for(int i=1;i<=len;i++){
			LL tmp=1ll*rhs*a[i]+x;
			x=tmp/lim;res.a[i]=tmp%lim;
		}
		while(x)res.a[++res.len]=x%lim,x/=lim;
		return res;
	}
	BigInt operator + (const int &rhs)const{
		BigInt res;int x=rhs;res.len=len;
		for(int i=1;i<=len;i++)
			res.a[i]=a[i]+x,x=res.a[i]/lim,res.a[i]%=lim;
		while(x)res.a[++res.len]=x%lim,x/=lim;
		return res;
	}
	int operator % (const int &rhs)const{
		int res=0;
		for(int i=len;i>0;i--)
			res=(1ll*res*lim+a[i])%rhs;
		return res;
	}
	void print(){
		if(!len){puts("0");return ;}printf("%d",a[len]);
		for(int i=len-1;i>0;i--)printf("%07d",a[i]);puts("");
	}
}A;
void init(){
	for(int i=2;i<=n;i++){
		if(!oula[i])prime[++cntp]=i;
		for(int j=1;j<=cntp&&1ll*i*prime[j]<=n;j++){
			oula[i*prime[j]]=1;
			if(i%prime[j]==0)break;
		}
	}
}
signed main(){
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	read(n);init();if(n==1){puts("1");return 0;}
	if(n<17){puts("No solution");return 0;}
	if(n<35){printf("%d\n",ans[n-17]);return 0;}
	A=BigInt(1);
	for(int i=1;i<=cntp;i++)if(prime[i]*prime[i]>n&&!oula[prime[i]+prime[i]+1]){a=prime[i];break;}
	for(int i=1;i<=cntp;i++)if(prime[i]!=a&&prime[i]!=a+a+1)A=A*prime[i];int b=a+a+1;
	int tmp1=A%a,tp1=1ll*(a-1)*qkpow(b*tmp1%a,a-2,a)%a;
	int tmp2=A%b,tp2=1ll*(a+1)*qkpow(a*tmp2%b,b-2,b)%b;
	int tp=(1ll*tp1*b+1ll*tp2*a)%(a*b);A=A*tp;
	A.print();
	return 0;
}

谢谢!!!

posted @ 2022-03-06 11:04  StaroForgin  阅读(13)  评论(0)    收藏  举报  来源