3.20省选练习(上午)

$T1$

尽管善意的出题人在题目上写了反演

但是和反演没什么关系吧,可以显然的发现,每个因数是可以单独计算的

那么对于每个因子分开扫一遍就好了,大概是一个类似单调队列的东西,复杂度期望能过

显然上面是错的,因为这样的话是累和,我们的$gcd$是一堆数相乘

那么还是考虑枚举$gcd,$主要是我一开始看成子串了...

那么这个时候就可以显然的计算$dp[i]$的长度了,答案就是$\sum_{l=1}^{n}l\times i\times C(dp[i],l)$

这个$dp$转移首先把所有可能的情况全都组合出来

枚举倍数$sum+=dp[x](i|x)$

#include <bits/stdc++.h>
#define mod 1000000007
#define int long long
#define MAXN 1000005
int n,cnt[MAXN],fac[MAXN],dp[MAXN],Ans;
signed main() 
{
    scanf("%lld",&n);
    for(int i=fac[0]=1;i<=n;i++) 
    {
        fac[i]=2ll*fac[i-1]%mod;
    }
    for(int i=1,x;i<=n;++i)
    {
        scanf("%lld",&x);
        ++cnt[x];
    }
    for(int i=MAXN-1,cur;i>1;i--)
    {
        cur=0;
        for(int j=i;j<MAXN;j+=i) 
        {
            cur+=cnt[j];
        }
        //我们记得反正是总长度
        //那么就把所有情况都计算了
        //又由于每种情况都有一个gcd,那么把不满足的减去就好了 
        if(!cur) continue;
        dp[i]=fac[cur-1]*cur%mod;
        for(int j=i+i;j<MAXN;j+=i) 
        {
            dp[i]=(dp[i]-dp[j]+mod)%mod;
        }
        Ans=(Ans+dp[i]*i%mod)%mod;
    }
    printf("%d\n",Ans);
    return 0;
}

 

$T2$

$x^a+y^b=z^c(\mod M)$

给定$a,b,c$

大概给了你幂,让你求底数使得相等

构造的话很有意思,大概构造成这种形式$2^{kab}+2^{kab}=2^{kab+1}$

显然可以构造出一组解,那就好了

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
ll a,b,c,T,mod,l,k,x,y,z;
void exgcd(ll a0,ll b0,ll &x,ll &y)
{
    if(b0==0)
    {
        x=1;
        y=0;
        return;
    }
    exgcd(b0,a0%b0,y,x);
    y-=(a0/b0)*x;
}
ll my_pow(ll x,ll y){
    ll res=1;
    while(y)
    {
        if(y&1) 
        {
           res=(res*x)%mod;
        }
        x=(x*x)%mod;
        y>>=1;
    }
    return res%mod;
}
int main(){
    scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld",&mod);
        scanf("%lld%lld%lld",&a,&b,&c);
        l=0,k=0;
        exgcd(c,a*b,l,k);
        k=-k;
        if(k<0)
        {
            ll p=(-k)/c+1;
            k=k+c*p;
            l=l+p*a*b;
        }
        else if(k>0)
        {
            ll p=k/c;
            k-=p*c;
            l-=p*a*b;
        }
        x=my_pow(2,k*b);
        y=my_pow(2,k*a);
        z=my_pow(2,l);
        if(x==0||y==0||z==0)
        {
            if(a>1)
            {
                x=mod/2;
                y=1;z=1;
            }
            else if(b>1)
            {
                y=mod/2;
                x=1;z=1;
            }
            else if(c>1)
            {
                x=y=z=mod/2;
            }
            else 
            {
                x=1,y=1,z=2;
            }
        }
        printf("%lld %lld %lld\n",x,y,z);
    }
}

 

$T3$

大概是个组合数$?$

推出来了式子$Ans=\sum_{k=0}^{n}C(m,k)C(m-k,2\times(n-k))Num_k$

现在我们选出了哪些列选的方案数,那么我们就需要对于这种方案求出多少种行的方案数

大概就是我们现在每行有两个颜色相同的球,然后放到不同盒子(容量不同的方案数)

递推加容斥,枚举多少个盒子里面有两个相同颜色的球

$S_k=\frac{1}{2^{n+k}}\sum_{i=0}^{k}(^k_i)(^n_i)i!(-1)^i2^i(2n-2i)!$

那么直接求就好了

#include<bits/stdc++.h>
#define MAXN 4000005
#define mod 998244353
#define int long long
using namespace std;
const int G=3,Ginv=(mod+1)/3;
int n,m,ans;
int rev[MAXN],jc[MAXN],inv[MAXN],S[MAXN],A[MAXN];
int my_pow(int a,int b)
{
    int res=1;
    while(b)
    {
          if(b&1) 
          {
               res=(res*a)%mod;
          }
          a=(a*a)%mod;
          b>>=1;
    }
    return res;
}
void NTT(int *A,int lim,int opt)
{
    for(int i=0;i<lim;++i) 
    {
        rev[i]=(rev[i>>1]>>1)|(i&1?(lim>>1):0);
    }
    for(int i=0;i<lim;++i) 
    {
        if(i<rev[i])
        {
            swap(A[i],A[rev[i]]);
        }
    }
    int len;
    int wn,w,x,y;
    for(int mid=1;mid<lim;mid<<=1)
    {
        len=mid<<1;
        wn=my_pow(opt==1?G:Ginv,(mod-1)/len);
        for(int j=0;j<lim;j+=len)
        {
            w=1;
            for(int k=j;k<j+mid;++k,w=w*wn%mod)
            {
                x=A[k];y=A[k+mid]*w%mod;
                A[k]=(x+y)%mod;A[k+mid]=(x-y+mod)%mod;
            }
        }
    }
    if(opt==1)return;
    int ni=my_pow(lim,mod-2);
    for(int i=0;i<lim;++i)A[i]=A[i]*ni%mod;
}
void MUL(int *A,int n,int *B,int m)
{
    int lim=1;
    while(lim<=(n+m))lim<<=1;
    NTT(A,lim,1);NTT(B,lim,1);
    for(int i=0;i<lim;++i)A[i]=A[i]*B[i]%mod;
    NTT(A,lim,-1);
}
void init(int Maxn)
{
    jc[0]=jc[1]=1;
    inv[0]=inv[1]=1;
    for(int i=1;i<=Maxn;++i)
    {
        jc[i]=jc[i-1]*i%mod;
    }
    inv[Maxn]=my_pow(jc[Maxn],mod-2);
    for(int i=Maxn-1;i>=1;--i)
    {
        inv[i]=inv[i+1]*(i+1)%mod;
    }
}
int C(int n,int m)
{  
    if(n<m)return 0;
    return jc[n]*inv[m]%mod*inv[n-m]%mod;
}
signed main()
{
//    freopen("c.in","r",stdin);
//    freopen("c.out","w",stdout);
    cin>>n>>m;
    init(2*max(n,m));
    for(int i=0;i<=n;++i)
    {
        S[i]=inv[i];
        A[i]=(i&1?-1:1)*my_pow(2,i)*jc[2*n-2*i]%mod*inv[n-i]%mod*inv[i]%mod;
    }
    MUL(S,n,A,n);
    for(int i=0;i<=n;++i)
    {
       (ans+=C(m,i)*C(m-i,2*(n-i))%mod*my_pow(2,(n+i)*(mod-2))%mod*jc[i]%mod*jc[n]%mod*S[i])%=mod;    
    }
    cout<<(ans%mod+mod)%mod;
    return 0;
}

 

posted @ 2022-03-20 11:24  Authentic_k  阅读(30)  评论(0编辑  收藏  举报