• 【题解】JXOI2018游戏(组合数)


    【题解】JXOI2018游戏(组合数)

    题目大意

    对于([l,r])中的数,你有一种操作,就是删除一个数及其所有倍数。问你删除所有数的所有方案的步数之和。 由于这里是简化题意,有一个东西没有提到: 你可以“删除”已经被删除的点。而且即使你已经删掉了所有的数,若你仍然要继续操作直到做了(r-l+1)不同的删除动作。这将计入方案。

    可能还是没有讲清楚,可以去康康原题...

    实际上我想写一下题解是因为一个思想的方法...

    考虑将([l,r])每一个数向他的倍数连边。这可以形成一个拓扑图。删除一个点(x)的效果就是将拓扑图中所有能被(x)到达的点删掉。那么删除整张图的充分必要条件是所有入度数为(0)的点被删除掉。那么考虑那些入度为(0)的数是哪些。一些数被连边是由于在区间中存在他的因数,所以一个数没有被进入是因为他的最大约数小于边界(l)。考虑如何筛选出最大约数小于某个值的数,可以让这个数除去他的最小因子——最小因子=最小的质因子。所以可以直接线性筛所有数的最小质因子即可。

    其实上面这段话可以用三个显然概括掉,但是我想记录一下这个思路,所以写得很啰嗦清晰。

    考虑一个删数的方案其实是一个排列。记(n=r-l+1,m=)入度等于0的点个数。

    枚举删除需要(i)步,也就说(m)个数字要在第(i)位正好全部出现。那么对于前面(i ge m)个位置,先钦定一个放在第(i)位也就是(m choose 1),然后剩下的随便排列就是((m-1)!)但是有一些缺的位置那么从后面选点过来填上就是(A_{n-m}^{i-m}) 然后剩下的数随便排列也就是((n-i)!)

    最终答案:

    [sum_{mle ile n} i{mchoose 1}(m-1)!{n-mchoose i-m}(i-m)!(n-i)! ]

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(c<48||c>57)f|=c==45,c=getchar();
          while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    
    const int maxn=1e7+5;
    const int mod=1e9+7;
    int usd[maxn],Min[maxn];
    int jc[maxn],inv[maxn];
    vector<int> ve;
    inline int ksm(const int&base,const int&p){
          int ret=1;
          for(int t=p,b=base%mod;t;t>>=1,b=1ll*b*b%mod)
    	    if(t&1) ret=1ll*ret*b%mod;
          return ret;
    }
    inline void pre(const int&n){
          jc[0]=inv[0]=1;
          for(register int t=1;t<=n;++t) jc[t]=1ll*jc[t-1]*t%mod;
          inv[n]=ksm(jc[n],mod-2);
          for(register int t=n-1;t;--t) inv[t]=1ll*inv[t+1]*(t+1)%mod;
          Min[1]=10; usd[1]=1;
          for(register int t=2;t<=n;++t){
    	    if(!usd[t]) ve.push_back(t),Min[t]=t;
    	    for(register auto i:ve){
    		  if(1ll*i*t>n) break;
    		  usd[i*t]=1;
    		  Min[i*t]=min(Min[t],i);
    		  if(t%i==0) break;
    	    }
          }
    }
    
    inline int c(const int&n,const int&m){
          if(n<m)return 0;
          return 1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;
    }
    
    int l,r,m,n;
    int main(){
          l=qr(); r=qr();
          n=r-l+1;
          pre(r+3);
          for(register int t=l;t<=r;++t) if(t<1ll*l*Min[t]) ++m;
          int ans=0;
          for(register int t=m,ret;t<=n;++t){
    	    ret=1ll*t%mod*m%mod*c(n-m,t-m)%mod*jc[t-1]%mod*jc[n-t]%mod;
    	    ans=(ans+ret)%mod;
          }
          printf("%d
    ",ans);
          return 0;
    }
    
    
  • 相关阅读:
    execution(* *..BookManager.save(..))的解读
    metalink下载补丁包
    loop_login.sh
    EXPDP IMPDP 知识总结
    图书管理系统简单 过程
    Data Types
    Oracle 创建分页存储过程(转帖)
    绑定变量赋值
    Oracle10g、 Oracle11g完美共存
    Oracle11G 数据库 expdp、impdp使用示例
  • 原文地址:https://www.cnblogs.com/winlere/p/11568831.html
Copyright © 2020-2023  润新知