zoukankan      html  css  js  c++  java
  • 【题解】space

    jzoj5970

    题目大意:有(n^4)个点((a,b,c,d)(1leqslant a,b,c,dleqslant n)),给出(4)个长度为(n)的排列(A,B,C,D),表示从((a,b,c,d))连向((A_a,B_b,C_c,D_d))的边长度为(1),连向其它所有点的边长度为(2),求最短汉密尔顿回路长度。

    由于要经过每个点一次,所以一定经过了(n^4)条边。所以可以将所有边的长度减(1),最后统计答案时再加回去。

    取出所有此时长度为(0)的边,构成一个新图。显然每个点的出度为(1),又由于(A,B,C,D)是排列,所以每个点的入度也为(1),于是这个新图一定是有若干个环(可能有自环)组成。

    每个环内的边的长度为(0),所以可以考虑把每一个环缩成一个点,任意两个缩环后的点之间的距离为(1)。容易发现,当图中只有(1)个环,则不需要在环间走,否则,在环之间走的最短长度为环的数量。

    如何求出环的数量?

    设两个大小为(n)(m)的环合并表示:两个长度分别为(n,m)的排列(A,B),满足(A_i=i\%n+1,B_i=i\%m+1),有(n imes m)个点((i,j)(1leqslant ileqslant n,1leqslant jleqslant m))((i,j))((A_i,B_j))连边,所得的图上的所有的环。

    不难发现,两个大小为(n)(m)的环合并会形成(gcd(n,m))个大小为( ext{lcm}(n,m))的环,记为(notimes m=gcd(n,m) imes ext{lcm}(n,m)),环的合并满足交换律和结合律。

    设两个环的可重复集合(A,B)合并为(C=sum_{iin A,jin B}iotimes j),也满足交换律和结合律。

    于是,原问题可以转化为(sum_{i=1}^nsum_{j=1}^nsum_{k=1}^nsum_{l=1}^nfrac{ijkl}{ ext{lcm}(ijkl)}A_iB_jC_kD_l),其中(A_i)表示第一个排列中的环的数量,(B,C,D)同理。

    同时合并(4)个集合不好做,可以考虑两两合并。

    (sum_{i=1}^niA_i=n)可以看出(sum_{i=1}^n[A_i eq0]leqslant 2sqrt{n}),就可以暴力取出( eq0)(A_i,B_i)(O(nlog n))(A)(B)合并,得到一个新的集合(E),同理合并(C,D)得到(F)(E)(F)中不为(0)的项的数量是(O(n))的。

    合并(E,F)可以考虑分块,设一个(lim),对于(i,jleqslant lim)的,用两个数组(p,q)分别存下,相当于求(sum_{i=1}^{lim}sum_{j=1}^{lim}p_iq_jgcd(i,j)),反演+变换消去(gcd)可以(O(limlog lim))求。对于(i>lim)或者(j>lim)的部分,最多有(frac{n^2}{lim})个数,暴力(O(ncdotfrac{n^2}{lim}log lim))两两合并即可。

    总复杂度(O((lim+frac{n^3}{lim})log lim)),跑不满,常数小,松得过。

    code:

    #include<stdio.h>
    #include<vector>
    #include<algorithm>
    #define inf 998244353
    #define S 2000000
    #define R(a,b,c) 
    	for(int i=1;i<=n;i++)scanf("%d",&pos[i]),mk[i]=1;
    	for(int i=1;i<=n;i++)if(mk[i]){
    		int p=i,cnt=0;
    		while(mk[p])cnt++,mk[p]=0,p=pos[p];
    		a[cnt]++;
    	}for(int i=1;i<=n;i++)if(a[i])b[++c]=std::make_pair(i,a[i]);
    inline long long gcd(long p,long q){while(p%=q)p^=q^=p^=q;return q;}
    int a[100002],b[100002],c[100002],d[100002],pos[100002],mk[10000002],n,tpa=0,tpb=0,tpc=0,tpd=0,tpA=0,tpB=0;
    std::pair<long long,int>aa[100002],bb[100002],cc[100002],dd[100002],A[1000002],B[1000002],AA[1000002],BB[1000002];
    int a1[S+2],b1[S+2],ans=0,p[S+2],tp=0;
    int main(){
    //	freopen("space.in","r",stdin);
    //	freopen("space.out","w",stdout);
    	scanf("%d",&n);
    	R(a,aa,tpa);
    	R(b,bb,tpb);
    	R(c,cc,tpc);
    	R(d,dd,tpd);
    	for(int i=2;i<=S;i++){
    		if(!mk[i])p[++tp]=i;
    		for(int j=1;j<=tp&&i*p[j]<=S&&(mk[i*p[j]]=1)&&i%p[j];j++);
    	}
    	for(int i=1;i<=tpa;i++)
    		for(int j=1;j<=tpb;j++){
    			int p=gcd(aa[i].first,bb[j].first);
    			AA[(i-1)*tpb+j]=std::make_pair(aa[i].first*bb[j].first/p,1ull*aa[i].second*bb[j].second*p%inf);
    		}std::sort(AA+1,AA+tpa*tpb+1);
    	A[tpA=1]=AA[1];
    	for(int i=2;i<=tpa*tpb;i++){
    		if(AA[i].first!=AA[i-1].first)A[++tpA].first=AA[i].first,A[tpA].second=0;
    		A[tpA].second+=AA[i].second;
    		if(A[tpA].second>=inf)A[tpA].second-=inf;
    	}
    	for(int i=1;i<=tpc;i++)
    		for(int j=1;j<=tpd;j++){
    			int p=gcd(cc[i].first,dd[j].first);
    			BB[(i-1)*tpd+j]=std::make_pair(cc[i].first*dd[j].first/p,1ull*cc[i].second*dd[j].second*p%inf);
    		}std::sort(BB+1,BB+tpc*tpd+1);
    	B[tpB=1]=BB[1];
    	for(int i=2;i<=tpc*tpd;i++){
    		if(BB[i].first!=BB[i-1].first)B[++tpB].first=BB[i].first,B[tpB].second=0;
    		B[tpB].second+=BB[i].second;
    		if(B[tpB].second>=inf)B[tpB].second-=inf;
    	}
    	for(int i=tpA;i;i--)
    		for(int j=tpB;j&&(A[i].first>S||B[j].first>S);j--)
    			ans=(1ull*A[i].second*B[j].second%inf*gcd(A[i].first,B[j].first)+ans)%inf;
    	for(int i=1;i<=tpA&&A[i].first<=S;i++)
    		a1[A[i].first]=A[i].second;
    	for(int i=1;i<=tpB&&B[i].first<=S;i++)
    		b1[B[i].first]=B[i].second;
    	for(int i=1;i<=S;i++)
    		for(int j=i<<1;j<=S;j+=i)
    			a1[i]+=a1[j],a1[i]-=a1[i]>=inf?inf:0;
    	for(int i=1;i<=S;i++)
    		for(int j=i<<1;j<=S;j+=i)
    			b1[i]+=b1[j],b1[i]-=b1[i]>=inf?inf:0;
    	for(int i=1;i<=S;i++)
    		a1[i]=1ull*a1[i]*b1[i]%inf;
    	for(int j=1;j<=tp;j++){
    		for(int i=1;i*p[j]<=S;i++)
    			a1[i]+=inf-a1[i*p[j]],a1[i]-=a1[i]>=inf?inf:0;
    	}for(int i=1;i<=S;i++)ans=(1ull*a1[i]*i+ans)%inf;
    	printf("%d
    ",(1ull*n*n*n%inf*n+ans)%inf);
    }
    
  • 相关阅读:
    cnblog项目--20190309
    django js引入失效问题
    Python老男孩 day16 函数(六) 匿名函数
    Python老男孩 day16 函数(五) 函数的作用域
    Python老男孩 day15 函数(四) 递归
    Python老男孩 day15 函数(三) 前向引用之'函数即变量'
    Python老男孩 day15 函数(二) 局部变量与全局变量
    Python老男孩 day14 函数(一)
    Python老男孩 day14 字符串格式化
    Python老男孩 day14 集合
  • 原文地址:https://www.cnblogs.com/ztc03/p/12025033.html
Copyright © 2011-2022 走看看