zoukankan      html  css  js  c++  java
  • bzoj 3202 [Sdoi2013]项链——容斥+置换+推式子

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3202

    可见Zinn博客:https://www.cnblogs.com/Zinn/p/10073897.html

    关于算有序三元组那个部分,自己觉得是这样解释:

    这样标号的话,旋转置换有2个:(1,2,3)和(1,3,2); 不动的话是一个置换:(1)(2)(3); 翻转的话,贴着一个侧面所在的面上下翻转,就是三个置换:(1)(2,3)、(2)(1,3)、(3)(1,2)。根据Polya定理算不动点个数,就是 ( frac{1}{6}(2*g(1)+g(3)+3*g(2) ) ,其中 g(x) 表示选 x 个数且其gcd=1的方案数。(比如 (1,2,3) ,如果“不动”的话,3个位置的数都要一样,即找1个数,是g(1);(1)(2,3)的话,2、3位置的数一样,即找两个数,是g(2))。

    通过 dfs 质因数的幂来找出所有约数的方法很好,因为可以顺便做出 phi 。

    注释掉的那个快速乘好像会 WA ?

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=1e7+5,mod=1e9+7,base=1e5;
    ll M=(ll)(1e9+7)*(ll)(1e9+7);//(ll)!!!!!
    int a,T,pri[N],cnt;ll n,t,u[N],ans,p[65],q[65],tot,tmd;
    bool vis[N],fx;
    void upd(ll &x,ll md){x>=md?x-=md:0;x<0?x+=md:0;}
    /*ll mul(ll a,ll b,ll md)
    {ll ret=0;while(b){if(b&1ll)ret+=a,upd(ret,md);a+=a;upd(a,md);b>>=1ll;}return ret;}*/
    /*ll mul(ll a,ll b,ll md)//slow and WA?
    {
      ll bs=(md==M?mod:base);
      ll A=a/bs,B=a%bs,C=b/bs,D=b%bs;
      ll ret=A*C%md*bs%md*bs%md;
      ret=(ret+A*D%md*bs)%md;
      ret=(ret+B*C%md*bs)%md;
      ret=(ret+B*D)%md;
      return ret;
      }
    */
    ll mul(ll a,ll b,ll md)
    {
      return (a*b-(ll)( ((long double)a*b+0.5)/(long double)md )*md+md)%md;
    }
    ll pw(ll x,ll k,ll md)
    {x%=md;k%=(md-1);ll ret=1;while(k){if(k&1)ret=mul(ret,x,md);x=mul(x,x,md);k>>=1;}return ret;}
    void calc(ll md)
    {
      ll g2=0,g3=0;
      for(int i=1,j,d;i<=a;i=j+1)
        {
          d=a/i; j=a/d; ll k=u[j]-u[i-1];upd(k,md);
          ll tmp=mul(mul(d,d,md),k,md);
          g2=g2+tmp; upd(g2,md);
          tmp=mul(tmp,d,md);
          g3=g3+tmp; upd(g3,md);
        }
      t=(g3+3*g2+2)%md;
      t=mul(t,pw(6,fx?M-mod-1:mod-2,md),md);//phi(M)=mod*(mod-1)
    }
    void init()
    {
      memset(vis,0,sizeof vis); cnt=0;
      u[1]=1;  ll d;
      for(int i=2;i<=a;i++)
        {
          if(!vis[i])u[i]=-1,pri[++cnt]=i;
          for(int j=1;j<=cnt&&(d=(ll)i*pri[j])<=a;j++)
        {
          vis[d]=1;u[d]=-u[i];
          if(i%pri[j]==0){u[d]=0;break;}
        }
        }
      for(int i=2;i<=a;i++)u[i]+=u[i-1],upd(u[i],tmd);
      calc(tmd);
    }
    ll F(ll x,ll md)
    {
      ll ret=0;
      if(x&1ll)ret=1-t; else ret=t-1;
      upd(ret,md);
      ret+=pw(t-1,x,md); upd(ret,md);
      return ret;
    }
    ll Phi(ll x,ll md)
    {
      ll ret=x,yx=x;
      for(ll d=2;d*d<=x;d++)
        if(x%d==0)
          {
        ret/=d; ret*=(d-1);
        while(x%d==0)x/=d;
          }
      if(x>1)ret/=x,ret*=(x-1);
      return ret%md;
    }
    void cal(ll x)
    {
      tot=0;
      for(ll i=2;i*i<=x;i++)
        if(x%i==0)
          {
        p[++tot]=i;q[tot]=0;
        while(x%i==0)x/=i,q[tot]++;
          }
      if(x>1)p[++tot]=x,q[tot]=1;
    }
    void dfs(int cr,ll nw,ll phi)
    {
      if(cr>tot){ans+=mul(F(n/nw,tmd),phi,tmd);upd(ans,tmd);return;}
      dfs(cr+1,nw,phi);
      nw*=p[cr];phi*=p[cr]-1;//needn't tmd
      dfs(cr+1,nw,phi);
      for(int i=2;i<=q[cr];i++)
        nw*=p[cr],phi*=p[cr],dfs(cr+1,nw,phi);
    }
    int main()
    {
      scanf("%d",&T);
      while(T--)
        {
          scanf("%lld%d",&n,&a);
          fx=(n%mod==0); if(fx)tmd=M; else tmd=mod;
          init();  ans=0;
          cal(n); dfs(1,1,1);
          /*
          for(ll d=1;d*d<=n;d++)//d=1
        if(n%d==0)
          {
            ll k=n/d;
            ans+=mul(F(d,md),Phi(k,md),md); upd(ans,md);
            if(k!=d)ans+=mul(F(k,md),Phi(d,md),md), upd(ans,md);//mul
          }
          */
          if(fx)ans/=mod,ans=ans*pw(n/mod,mod-2,mod)%mod;
          else ans=ans*pw(n,mod-2,mod)%mod;
          printf("%lld
    ",ans);
        }
      return 0;
    }
  • 相关阅读:
    guaguia
    webapp手机移动端开发技巧
    两个数组对象对比
    json 根据某个子,寻找父节点的算法
    递归写法
    数组归类
    视频点击按钮下载
    微信小程序 直接跳转到首页
    iframe 跨域传值
    判断对象是否为空
  • 原文地址:https://www.cnblogs.com/Narh/p/10074544.html
Copyright © 2011-2022 走看看