loj2544 「JXOI2018」游戏
自己太傻,一遇到有关数学的题就懵逼,这种简单题竟然还得靠NicoDafaGood
在$[l,r]$这个区间内,如果没有数是$x$的因数,我们称$x$为好数。
我们就只需要考虑这些好数中最靠后的那一个的位置,因为这些好数,我们必须取,而且是充分必要条件。
那么我们算得了好数的个数,问题就转化成,有一堆0和1,问所有排列方式,最后一个1的位置的和。
或者说,算最后的连续的0的个数的和。
明显可以随便递推转移一下。
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i>=(b);--i) const ll mod=1e9+7,maxn=1e7+7; ll n,m,dp[maxn],mi[maxn]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int prime[maxn],num[maxn],totp; bool ok[maxn]; void get_p() { num[1]=2; For(i,2,m) { if(!ok[i]) num[i]=i,prime[++totp]=i; For(j,1,totp) { if(prime[j]>m/i) break; ok[i*prime[j]]=1; num[i*prime[j]]=prime[j]; if(i%prime[j]==0) break; } } } int main() { read(n); read(m); get_p(); ll x,sum=0,o=m-n+1; For(i,n,m) { x=i/num[i]; if(x<n) ++sum; } dp[0]=1; o-=sum; For(i,1,o) dp[i]=dp[i-1]*(o-i+1)%mod; mi[0]=1; For(i,1,o+sum) mi[i]=mi[i-1]*i%mod; For(i,0,o) dp[i]=dp[i]*mi[sum+o-i]%mod; For(i,0,o) dp[i]=(dp[i]-dp[i+1]+mod)%mod; ll rs=0; For(i,0,o) rs+=dp[i]*(sum+o-i)%mod; printf("%lld\n",rs%mod); return 0; }
弱者就是会被欺负呀