• 牛客挑战赛45 G 致两千年后的你


    给出(a_i),对于集合(S),定义(f_0(S)=1)当且仅当存在任意钦定的系数(c_i),使得(sum_{iin S}a_ic_iequiv xpmod P),否则(f_0(S)=0)

    定义(f_i(S)=sum_{Tsubseteq S}f_{i-1}(T))

    (f_k(U))(U)为全集。

    (Tle 20,nle 3*10^5)

    (1le xle 10^{18})(2le P le 10^{18})(1le kle 10^9)

    保证(P)的最大质因数小于等于(3*10^5)


    不可拍的题。。。

    考虑第一部分:如何处理这个(f_0)

    以下先将(x)变成(xmod P)

    根据简单的数论知识,可以转化成如下问题:询问是否(gcd_{iin S}(gcd(a_i,P))|x)。原因大概根据式子(ax+by=gcd(a,b))得出。

    为了方便,接下来直接把(gcd(a_i,P))替换成(a_i)

    分解质因数,这个东西相当于:对于某个质因数(p_i),存在(a_i),满足这个质因数在(a_i)的指数小于等于在(x)中的指数。

    那么每个数可以用(01)(b_i)来表示,其中第(j)位表示(p_j)的指数是否小于等于(x)(p_j)的指数。

    于是(f_0(S)=[or_{iin S} b_i=U'])

    想到这里再搞另一个问题:如何通过(f_0)得到(f_k)

    如果用集合幂级数来表示,发现就是(f_k=f_0*I^k)

    思考一下卷(I^k)是什么:先选出一个子集,在这个子集中选出一个子集,再选……选(k-1)遍((I)是只选自己而不是子集,所以是(k-1))。如果将选看成加一,那么最终每个数在([0,k-1])中随机,每个位置有(k)种选择。于是(I^k(S)=k^{|S|})

    于是(f_k(U)=sum_{S}f_0(S)k^{n-|S|}),提出(k^n),得到(f_k(U)=k^nsum_{S}f_0(S)k^{-|S|})。这启示着我们将(k^{-1})作为计算(f_0(S))时的系数。

    回来思考一下(f_0(S))如何计算。列出式子:(f_0=prod (1+k^{-1}x^{b_i}))。发现(FWT(1+k^{-1}x^{b_i})(S)=1+k^{-1}[b_0subseteq S])

    一项对(FWT(f_0(S)))的贡献为在(b_0subseteq S)处给(f_0(S))(1+k^{-1})。于是只需要计算(1+k^{-1})的指数。

    定义集合幂级数(g=sum {b_i})(FWT(f_0)(S)=(1+k^{-1})^{FWT(g)(S)}),可以算出(g)再算出(f)

    于是这道题就结束了。实现的时候要注意一点细节(拍不出来……),并且卡卡常。

    比如说给gcd的速度是很慢的,这时候需要指数取(min)。还有在算(b_i)的时候可以加点剪枝。


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 300005
    #define ll long long
    #define mo 1000000007
    #define INF 1000000000
    ll gcd(ll a,ll b){
    	while (b){
    		ll k=a%b;
    		a=b,b=k;
    	}
    	return a;
    }
    ll qpow(ll x,ll y=mo-2){
    	ll r=1;
    	for (;y;y>>=1,x=x*x%mo)
    		if (y&1)
    			r=r*x%mo;
    	return r;
    }
    int p[N],np;
    bool inp[N];
    void initp(int n){
    	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;
    		}
    	}
    }
    int n;
    ll x,k,P;
    ll a[N];
    int b[N];
    int c,d[17],e[17];
    int idx(ll &n,int p){
    	if (n==0) return INF;
    	int t=0;
    	while (n%p==0)
    		n/=p,++t;
    	return t;
    }
    bool judge(ll &n,int p,int lim){
    	int t=0;
    	while (t<=lim && n%p==0)
    		n/=p,++t;
    	return t<=lim;
    }
    void divide(ll n){
    	c=0;
    	for (int i=1;i<=np && n!=1;++i)
    		if (n%p[i]==0){
    			d[c]=p[i];
    			e[c]=idx(n,p[i]);
    			c++;
    		}
    	if (n!=1)
    		d[c]=n,e[c]=1,c++;
    }
    void initb(){
    	static int bx[N];
    	ll xx=x;
    	for (int j=0;j<c;++j)
    		bx[j]=idx(xx,d[j]);
    	for (int i=1;i<=n;++i){
    //		ll ai=gcd(a[i],P);
    		ll ai=a[i];
    		b[i]=0;
    //		if (ai==0) continue;
    		for (int j=0;j<c;++j){
    			if (e[j]<=bx[j]){
    				b[i]|=1<<j;
    				continue;
    			}
    			if (judge(ai,d[j],bx[j]))
    				b[i]|=1<<j;
    		}
    	}
    }
    ll g[1<<17];
    int main(){
    	freopen("in.txt","r",stdin);
    	freopen("out.txt","w",stdout);
    	int T;
    	scanf("%d%d",&n,&T);
    	for (int i=1;i<=n;++i)
    		scanf("%lld",&a[i]);
    	initp(300000);
    	while (T--){
    		scanf("%lld%lld%lld",&x,&k,&P);
    		x%=P;
    		divide(P);
    		initb();
    //		for (int i=1;i<=n;++i)
    //			printf("%d
    ",b[i]);
    //		printf("
    ");
    		memset(g,0,sizeof(ll)*(1<<c));			
    		for (int i=1;i<=n;++i)
    			g[b[i]]++;
    		for (int i=1;i<1<<c;i<<=1)
    			for (int j=0;j<1<<c;j+=i<<1)
    				for (int k=0;k<i;++k)
    					g[j+k+i]+=g[j+k];
    		ll tmp=1+qpow(k);
    		for (int i=0;i<1<<c;++i)
    			g[i]=qpow(tmp,g[i]);
    		for (int i=1;i<1<<c;i<<=1)
    			for (int j=0;j<1<<c;j+=i<<1)	
    				for (int k=0;k<i;++k)
    					(g[j+k+i]-=g[j+k])%=mo;
    		ll ans=(g[(1<<c)-1]+mo)%mo*qpow(k,n)%mo;
    		
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    关于运行和调试的困惑
    初识函数
    Php的基本语法
    Apache的安装
    php的初步了解
    线程笔记
    Matlab笔记
    matlab取模与取余
    DialogFragment学习笔记
    MVP学习笔记——参考Google官方demo
  • 原文地址:https://www.cnblogs.com/jz-597/p/13977888.html
Copyright © 2020-2023  润新知