loj2544 「JXOI2018」游戏

https://loj.ac/problem/2544

自己太傻,一遇到有关数学的题就懵逼,这种简单题竟然还得靠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;
}
posted @ 2018-06-21 18:31  shixinyi  阅读(313)  评论(0编辑  收藏  举报