zoukankan      html  css  js  c++  java
  • 6455. 【GDOI2020模拟02.01】小 D 的交通

    题目

    给你正整数(n),让你求任意一个(X),满足从(X)开始的连续(n)个整数通过以下条件联通:
    对于两个数(u)(v),假如(u)(v)不互质,那么它们之间就连上一条边。
    (nleq 100000)
    (记得打高精度)


    思考历程

    花了半天时间终于把题目换成了一个可以看的模型:
    对于所有小于(n)的质数(p_i)(p_i)的所有倍数(形如(X+i))都连在一起。
    题目的条件是(X+i equiv X+j equiv 0 (mod p_i))
    简单推一下就是(iequiv j equiv -X(mod p_i))
    (接下来为了方便,我直接将(-X)变成(X)
    于是就有了更好看的模型:对于数列(0..n-1),对于每个质数(p_i),钦定一个数(a_i),表示所有满足(xequiv a_i (mod p_i))的都连在一起。
    至于(X),做中国剩余定理就可以求出来了。
    现在的问题时怎么构造,而我不会……
    所以就暴力构造,如果合法就用中国剩余定理求。
    得分和纯暴力没有什么两样。


    正解

    先说一说一个更加优美些的暴力该怎么做。
    对于某个大于(frac{n}{2})的质数(p_i),很显然它只能连接两个点。
    由于考虑(p_1)(也就是(2))的时候就已经将距离为偶数的点连起来了,所以对于某个奇素数(p_i)连向了某个数(x),如果它没有在(p_1)的时候被连到,那么它连向的(x+p_i)(或(x-p_i))一定在(p_1)的时候被连到了(因为(p_i)为奇数)
    所以,在暴力了(frac{n}{2})之前的质数之后,剩余的质数贪心地去捡漏就好了。
    题解说这样可以过掉(nleq 40),但实测出只能过(nleq 31)

    接下来就是题解的奇妙构造大法。
    考虑假如我们把第一个点(也就是(0))作为核心点(就是(a_iequiv 0 (mod p_i))),就会发现除了第二个点((1))之外,其它的点都会被接上。
    于是我们考虑怎么让它被连到。
    然而在这个情况下,已经没有素数供我们使用了。
    考虑将核心点放在中间(记为(mid)),容易发现只有(mid-1)(mid+1)没有被连上。
    找到最大的小于(frac{n}{2})的两个素数,分别将(mid-1)(mid+1)连上。
    由于这两个素数被侵占了,所以会多出几个位置没有连上。
    (frac{n}{2})以上的素数我们还没有用过,那就随便连连即可。
    接下来有个问题:有没有可能素数不够用??
    实践表明,有这种情况……在(nleq 31)的时候还是自己跑暴力吧。
    不过更大的数,似乎都可以(这就要靠实践了……)
    我猜想(n>31)都可以用这个方式构造出来,但是不会证。
    如果能证的话,GMH大爷提供了一条定理,可以参考一下:
    伯特兰-切比雪夫定理


    代码

    
    SRC Download 
    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    #define N 100010
    #define ll long long
    ll qpow(ll x,int y,int mo){
    	ll res=1;
    	for (;y;y>>=1,x=x*x%mo)
    		if (y&1)
    			res=res*x%mo;
    	return res;
    }
    int n;
    int p[N],np;
    bool inp[N];
    int a[N];
    int dsu[N];
    int getdsu(int x){return dsu[x]==x?x:dsu[x]=getdsu(dsu[x]);}
    #define BIT 1000000
    struct Bigint{
    	int k;
    	ll v[N];
    	void print(){
    		printf("%lld",v[k]);
    		for (int i=k-1;i>=0;--i)
    			printf("%06lld",v[i]);
    	}
    };
    inline void operator+=(Bigint &A,Bigint &B){
    	for (int i=0;i<=A.k || i<=B.k;++i){
    		A.v[i]+=B.v[i];
    		A.v[i+1]+=A.v[i]/BIT;
    		A.v[i]%=BIT;
    	}
    	A.k=max(A.k,B.k);
    	if (A.v[A.k+1])
    		A.k++;
    }
    inline void operator*=(Bigint &A,int x){
    	for (int i=0;i<=A.k;++i)
    		A.v[i]*=x;
    	for (int i=0;i<=A.k;++i){
    		A.v[i+1]+=A.v[i]/BIT;
    		A.v[i]%=BIT;
    	}
    	if (A.v[A.k+1])
    		A.k++;
    }
    inline void operator*=(Bigint &A,Bigint &B){
    	static Bigint C;
    	memset(C.v,0,sizeof(ll)*(A.k+B.k+1+1));
    	for (int i=0;i<=A.k;++i)
    		for (int j=0;j<=B.k;++j)
    			C.v[i+j]+=A.v[i]*B.v[j];
    	for (int i=0;i<=A.k+B.k;++i){
    		C.v[i+1]+=C.v[i]/BIT;
    		C.v[i]%=BIT;
    	}
    	C.k=A.k+B.k;
    	if (C.v[C.k+1])
    		C.k++;
    	A.k=C.k;
    	memcpy(A.v,C.v,sizeof(ll)*(C.k+1));
    }
    Bigint pro,sum,Mi;
    int cnt,ai[N],mi[N];
    void calc(int mid){
    	pro.k=0;
    	pro.v[0]=1;
    	for (int i=1;i<=np;++i)
    		if (a[i]==0)
    			pro*=p[i];
    		else{
    			++cnt;
    			ai[cnt]=a[i];
    			mi[cnt]=p[i];
    		}
    	for (int i=1;i<=cnt;++i){
    		memset(Mi.v,0,sizeof(ll)*(Mi.k+1));
    		Mi.k=0,Mi.v[0]=1;
    		ll ti=1;
    		for (int j=1;j<=cnt;++j)
    			if (i!=j){
    				Mi*=mi[j];
    				ti=ti*mi[j]%mi[i];
    			}
    		Mi*=pro;
    		ll tmp=0;
    		for (int j=pro.k;j>=0;--j)
    			tmp=(tmp*BIT+pro.v[j])%mi[i];
    		ti=ti*tmp%mi[i];
    		ti=qpow(ti,mi[i]-2,mi[i]);
    		Mi*=ti;
    		Mi*=ai[i];
    		sum+=Mi;
    	}
    	sum.v[0]-=mid;
    	for (int i=0;sum.v[i]<0;++i)
    		sum.v[i]+=BIT,sum.v[i+1]--;
    	if (sum.v[sum.k]==0)
    		sum.k--;
    	sum.print();
    }
    //////////////////
    int top[40][N];
    int gettop(int num,int x){return top[num][x]==x?x:top[num][x]=gettop(num,top[num][x]);}
    void dfs(int k){
    	if (k>np || p[k]>n>>1){
    		for (int i=np;i>=k;--i){
    			for (int j=0;j<n;++j)
    				if ((j-p[i]>=0 || j+p[i]<n) && j%2!=a[1] && gettop(k-1,j)==j){
    					if (j-p[i]>=0)
    						top[k-1][gettop(k-1,j)]=gettop(k-1,j-p[i]);
    					else if (j<gettop(k-1,j+p[i]))
    						top[k-1][gettop(k-1,j+p[i])]=gettop(k-1,j);
    					else
    						top[k-1][gettop(k-1,j)]=gettop(k-1,j+p[i]);
    					a[i]=j%p[i];
    					a[i]=(a[i]?p[i]-a[i]:0);
    					break;
    				}
    		}
    		for (int i=0;i<n;++i)
    			if (gettop(k-1,i)!=0)
    				return;
    		calc(0);
    		exit(0);
    	}
    	for (int i=0;i<p[k];++i){
    		memcpy(top[k],top[k-1],sizeof(int)*n);
    		a[k]=(i?p[k]-i:0);
    		for (int j=i;j+p[k]<n;j+=p[k]){
    			int x=gettop(k,j),y=gettop(k,j+p[k]);
    			if (x>y)
    				swap(x,y);
    			top[k][y]=x;
    		}
    		dfs(k+1);
    	}
    }
    ////////////////
    int main(){
    	freopen("teleports.in","r",stdin);
    	freopen("teleports.out","w",stdout);
    	scanf("%d",&n);
    	if (n==1){
    		printf("1
    ");
    		return 0;
    	}
    	if (n<17){
    		printf("No solution
    ");
    		return 0;
    	}
    	for (int i=2;i<n;++i){
    		if (!inp[i])
    			p[++np]=i;
    		for (int j=1;j<=np && i*p[j]<n;++j){
    			inp[i*p[j]]=1;
    			if (i%p[j]==0)
    				break;
    		}
    	}
    	if (n<32){
    		for (int i=0;i<n;++i)
    			top[0][i]=i;
    		dfs(1);
    		return 0;
    	}
    	int mid=n/2,used;
    	for (int i=1;i<=np && p[i]<=mid;++i)
    		a[i]=0,used=i;
    	a[used]=(-1+p[used])%p[used];
    	a[used-1]=1;
    	for (int i=0;i<n;++i)
    		dsu[i]=i;
    	for (int i=1;i<=used;++i){
    		int tmp=getdsu(mid+a[i]-p[i]);
    		for (int j=mid+a[i];j<n;j+=p[i])
    			dsu[getdsu(j)]=tmp;
    		for (int j=mid+a[i]-p[i]*2;j>=0;j-=p[i])
    			dsu[getdsu(j)]=tmp;	
    	}
    	int mai=getdsu(mid);
    	for (int i=0;i<n;++i)
    		if (getdsu(i)!=mai){
    			used++;
    			a[used]=(i-mid)%p[used];
    			a[used]=(a[used]<0?a[used]+p[used]:a[used]);
    			dsu[i]=mai;
    		}
    	for (int i=1;i<=np;++i)
    		a[i]=(a[i]?p[i]-a[i]:0);
    	calc(mid);
    	return 0;
    }
    

    总结

    实践出真知。

  • 相关阅读:
    ASE19团队项目 beta阶段 model组 scrum report list
    ASE19团队项目 beta阶段 model组 scrum7 记录
    ASE19团队项目 beta阶段 model组 scrum6 记录
    ASE19团队项目 beta阶段 model组 scrum5 记录
    ASE19团队项目 beta阶段 model组 scrum4 记录
    ASE19团队项目 beta阶段 model组 scrum3 记录
    ASE19团队项目 beta阶段 model组 scrum2 记录
    ASE19团队项目 beta阶段 model组 scrum1 记录
    【ASE模型组】Hint::neural 模型与case study
    【ASE高级软件工程】第二次结对作业
  • 原文地址:https://www.cnblogs.com/jz-597/p/12269091.html
Copyright © 2011-2022 走看看