zoukankan      html  css  js  c++  java
  • 【题解】CF338D GCD Table

    CF338D GCD Table

    [ ext{Solution} ]

    我们依次来考虑 (i,j) 需要满足的条件。

    首先,既然满足所有 (1leq lleq k) 满足 (gcd(i,j+l-1)=a_l,) 那么可以合理导出 (forall a_l,a_l|i o ext{lcm}(a)_{i=1}^{k}|i)

    也就是 (i) 应当是 ( ext{lcm}) 的倍数形式。

    那么,设最小公倍数为 (M,)(i=k imes M,) 有一个推论:(k=1) 最优。

    证明:若 (k ot =1,)(gcd(i,j+l-1)=gcd(k imes M,j+l-1))

    我们发现,(gcd) 的式子里面平白无故多了一个 (k.) 同时,假定 (j) 满足条件,那么当 (i) 取最小的时候,不合法当且仅当 (gcd(i,j+l-1)>a_l,) 而将 (i o M imes k) 并不会将答案变小,所以并不优。

    那么 (i) 的构造就显然了,直接取最小公倍数即可。

    考虑 (j) 如何构造。容易发现, (j) 需要满足的性质应该是 (a_l|j+l-1,) 也就是 (j+l-1equiv 0(mod a_l) o jequiv 1-l(mod a_l))

    于是这就是一堆同余方程组了,但我们还会发现 (a_l) 之间并不互质。所以我们需要 ExCRT 来解决。

    考虑无解,我们发现,解决方程组只是必要条件,直接带入检验即可。

    一些细节:

    • 注意解扩展中国剩余定理的时候,方程的解是相对于前 (k-1) 个方程的,所以对应解出来的数不能随便模别的数

    • 注意到扩展欧几里得的通解形如 (x=x_0+k imes frac{c}{gcd(a,b)}) 如果我们要让它最小就让它取正数后对 (frac{c}{gcd(a,b)}) 取模即可

    • 这题数据范围大,会爆,需要龟速乘

    • 当解要大的时候就算无解了,因为超出了表格的范围

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=2e4+10;
    int n,m,k,a[N],ans1=1,ans2;
    inline int gcd(int x,int y){return !y?x:gcd(y,x%y);}
    void Exgcd(int a,int b,int &x,int &y){
    	if(!b){
    		x=1;y=0;
    		return;
    	}
    	Exgcd(b,a%b,x,y);
    	int t=x;x=y;y=t-a/b*y;
    }
    inline int LCM(int x,int y){return x/gcd(x,y)*y;}
    inline int Min(int x,int y){return x>y?y:x;}
    inline int Max(int x,int y){return x<y?y:x;}
    int Mul(int x,int y,int p){
    	if(y<0)x=-x,y=-y;
    	int s=0;
    	while(y){
    		if(y&1)s=(s+x)%p;
    		x=(x+x)%p;y>>=1;
    	}
    	return s;
    }
    void solve(int *A,int *b,int len){
    	int M=b[1];
    	int xx=0;
    	for(int i=2;i<=k;++i){
    		int r=A[i]-xx;
    		int t,y;
    		int d=gcd(M,b[i]);
    		if(r%d!=0){
    			puts("NO");
    			exit(0);
    		}
    		Exgcd(M,b[i],t,y);
    		int nM=LCM(M,b[i]);
    		t=Mul(t,r/d,b[i]/d);
    		xx=(xx%nM+t%nM*M%nM)%nM;
    		if(M>m){
    			puts("NO");
    			exit(0);
    		}
    		M=nM;
    		xx%=M;xx+=M;xx%=M;
    	}
    	xx%=M;xx+=M;xx%=M;
    	if(xx==0)xx=M;
    	if(xx>m){
    		puts("NO");
    		exit(0);
    	}
    	ans2=xx;
    	for(int i=1;i<=k;++i){
    		if(gcd(ans1,ans2+i-1)!=a[i]){
    			puts("NO");
    			exit(0);
    		}
    	}
    	puts("YES");
    }
    int num[N];
    signed main(){
    // 	freopen("in.txt","r",stdin);
    	cin>>n>>m>>k;
    	for(int i=1;i<=k;++i)cin>>a[i];
    	for(int i=1;i<=k;++i){
    		ans1=LCM(ans1,a[i]);
    		if(ans1>n){
    			puts("NO");
    			return 0;
    		}
    	}
    	for(int i=1;i<=k;++i)num[i]=(((a[i]-i+1+a[i])%a[i])+a[i])%a[i];
    	solve(num,a,k);
    	return 0;
    }
    
  • 相关阅读:
    AngularJS 拦截器
    android的Log日志打印管理工具类(一)
    android的Home键的监听封装工具类(一)
    android开发SDcard 响应的文件相关处理(一)
    android开发时间和日期的代码实现工具类(一)
    android文件和图片的处理工具类(一)
    android的二进制和十六进制的相互转换工具类(一):
    android的color整理(一)
    android经典Demo(转载)
    Android 根据EditText搜索框ListView动态显示数据
  • 原文地址:https://www.cnblogs.com/h-lka/p/15375117.html
Copyright © 2011-2022 走看看