码迷,mamicode.com
首页 > 其他好文 > 详细

[JXOI2018]游戏

时间:2018-05-23 20:41:40      阅读:105      评论:0      收藏:0      [点我收藏+]

标签:string   bool   排列   nbsp   +=   style   筛法   全选   using   

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\n",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\n",ans);
  return 0;
}

 

[JXOI2018]游戏

标签:string   bool   排列   nbsp   +=   style   筛法   全选   using   

原文地址:https://www.cnblogs.com/pigba/p/9078790.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!