zoukankan      html  css  js  c++  java
  • [JXOI2018]游戏

    https://www.luogu.org/problemnew/show/P4562

    一道不错的题

    题意:给一个区间[l,r],当选择一个数i时,所有i的倍数都会被标记,然后对于一个[l,r]的排列,价值为到第几个数所有数都被标记,求所有排列价值之和

    我们找出这样的数,只有它自己能标记自己。可以利用素数筛法去做,对于一个数有i>=l的因子去标记这个数,最后没有被标记的数则为这种特殊的数

    发现当选完所有特殊的数时,这个序列就全选完了

    设总共有x个这种数

    然后枚举价值为i的序列,它左边放了x-1个特殊数,并在这个位置放了最后一个,这样就是组合数*阶乘

    就是c(i-1,x-1)*(jc[x]*jc[n-x])

    然后就可以了

    本题重点是筛法筛出特殊数

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=1e7+5;
    const int P=1e9+7;
    int l,r,n;
    ll jc[N],inv[N];
    int pri[N];
    bool g[N],c[N];
    ll qpow(ll x,ll y)
    {
      ll ret=1;
      while(y)
        {
          if(y&1) ret=ret*x%P;
          x=x*x%P;
          y>>=1;
        }
      return ret;
    }
    ll C(int n,int m)
    {
      return jc[n]*inv[m]%P*inv[n-m]%P;
    }
    int main()
    {
      scanf("%d%d",&l,&r);
      n=r-l+1;
      jc[0]=1;
      for(int i=1;i<=r;i++) jc[i]=jc[i-1]*i%P;
      inv[r]=qpow(jc[r],P-2);
      for(int i=r;i;i--) inv[i-1]=inv[i]*i%P;
      int tot=0,cnt=0;
      ll ans=0;
      if(l==1)
        {
          ll t=n;
          printf("%lld
    ",jc[n-1]*((1+t)*t/2%P)%P);
          return 0;
        }
      else
        {
          for(int i=2;i<=r;i++)
        {
          if(!g[i]) pri[++tot]=i;
          for(int j=1;j<=tot && i*pri[j]<=r;j++)
            {
              g[i*pri[j]]=1;
              if(i>=l) c[i*pri[j]]=1;
              if(i%pri[j]==0) break;
            }
        } 
          for(int i=l;i<=r;i++) cnt+=(!c[i]);
        }
      for(int i=n;i>=cnt;i--) ans+=C(i-1,cnt-1)*i%P,ans%=P;
      ans=ans*jc[cnt]%P*jc[n-cnt]%P;
      printf("%lld
    ",ans);
      return 0;
    }
  • 相关阅读:
    2016.7.31整机升级计划
    UVa 1588
    UVa1587
    Jzoj4714 公约数
    Jzoj4714 公约数
    Jzoj4713 A
    Jzoj4713 A
    Jzoj4711 Binary
    Jzoj4711 Binary
    Jzoj4710 Value
  • 原文地址:https://www.cnblogs.com/pigba/p/9078790.html
Copyright © 2011-2022 走看看