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

BZOJ 3930 【CQOI2015】 选数

时间:2017-02-12 21:16:57      阅读:184      评论:0      收藏:0      [点我收藏+]

标签:long   cst   代码   lap   http   stdout   pre   print   turn   

题目链接:选数

  MDZZ,这种SB题我都Wa了这么多发,彻底没救系列~

  首先,我们可以发现1,如果我们选了两个不同的数,那么它们的\(\gcd\)不会超过\(r-l+1\)。于是,我们可以设一个\(f_i\)表示任取\(n\)个数,它们的\(\gcd\)为\(ik\)的方案数,最后我们要的答案就是\(f_1\)。我们考虑容斥一下,在求\(f_i\)的时候,先把\([l,r]\)中是\(ik\)倍数的数全部拿出来,然后任意选\(n\)个,这样选出来的数他们的\(\gcd\)一定是\(ik\)的倍数。于是,我们只需减去\(f_{2i},f_{3i},\dots,f_{\lfloor \frac{r-l+1}{i}\rfloor i}\)即可。

  这样的话,有可能还有些数\(\gcd\)是\(ik\)的倍数我们却没统计到。由于这些未统计的\(\gcd\)肯定比\(r-l+1\)大,那么肯定是选了\(n\)个相同的数,于是这一部分就可以直接算了。

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 100010
#define mod 1000000007

using namespace std;
typedef long long llg;

int n,k,l,r;
llg f[maxn];

void gi(llg &x){if(x>=mod) x%=mod;}
llg mi(llg a,int b){
	llg s=1;
	while(b){
		if(b&1) s=s*a,gi(s);
		a=a*a,gi(a); b>>=1;
	}
	return s;
}

int main(){
	File("a");
	scanf("%d %d %d %d",&n,&k,&l,&r);
	int rr=min(r/k,r-l+1);
	for(int i=rr,x,y=rr*k,z;i;i--,y-=k){
		x=(r/y)-(l/y); if(l%y==0) x++; z=(y>=l);
		for(int j=i<<1;j<=rr;j+=i) f[i]-=f[j],(f[i]+=mod)%=mod,z+=(j*k>=l);
		f[i]+=mi(x,n)-x+z; (f[i]+=mod)%=mod;
	}
	printf("%lld",(f[1]+mod)%mod);
	return 0;
}

BZOJ 3930 【CQOI2015】 选数

标签:long   cst   代码   lap   http   stdout   pre   print   turn   

原文地址:http://www.cnblogs.com/lcf-2000/p/6391669.html

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