【BZOJ】【3930】【CQOI2015】选数
数论/莫比乌斯反演/快速mu前缀和
比较容易想到令f[x]表示gcd=x的方案数,令g[x]表示x|gcd的方案数。
那么有$ g(d)=\sum_{d|n} f(n)$,根据莫比乌斯反演,有$f(d)=\sum_{d|n} g(n)*\mu (\frac{n}{d})$
我一开始想的是算出g以后,倒序枚举 i ,然后枚举 i 的倍数,递推出所有的f[i]……
因为g比较好算嘛……快速幂一下什么的……
然而$10^9$直接吓傻我。
Orz PoPoQQQ
快速求出mu的前缀和,$10^9$也照样不虚,太神辣
1 /************************************************************** 2 Problem: 3930 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:4200 ms 7 Memory:54024 kb 8 ****************************************************************/ 9 10 //BZOJ 3930 11 #include<cstdio> 12 #include<map> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 typedef long long LL; 23 inline int getint(){ 24 int r=1,v=0; char ch=getchar(); 25 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 26 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 27 return r*v; 28 } 29 const int N=1e7+1000,P=1e9+7; 30 const int INF=0x3f3f3f3f; 31 /*******************template********************/ 32 33 int mu[N],prime[1001001],tot; 34 bool check[N]; 35 map<int,LL> mu_sum; 36 LL n,d,l,r; 37 void getmu(){ 38 int n=10000000; 39 mu[1]=1; 40 F(i,2,n){ 41 if (!check[i]){ 42 mu[i]=-1; 43 prime[++tot]=i; 44 } 45 F(j,1,tot){ 46 int k=i*prime[j]; 47 if (k>n) break; 48 check[k]=1; 49 if (i%prime[j]) mu[k]=-mu[i]; 50 else{ 51 mu[k]=0; 52 break; 53 } 54 } 55 } 56 F(i,1,n) mu[i]+=mu[i-1]; 57 } 58 LL Mu_sum(int x){ 59 if (x<=10000000) return mu[x]; 60 if (mu_sum.find(x)!=mu_sum.end()) 61 return mu_sum[x]; 62 LL i,last,re=1; 63 for(i=1;i<=x;i=last+1){ 64 last=x/(x/i); 65 if (x/i-1) 66 re-=(Mu_sum(last)-Mu_sum(i-1))*(x/i-1); 67 } 68 return mu_sum[x]=re; 69 } 70 LL Pow(LL a,int b){ 71 LL r=1; 72 for(;b;b>>=1,a=a*a%P) if (b&1) r=r*a%P; 73 return r; 74 } 75 LL solve(){ 76 LL i,last,re=0; 77 for(i=1;i<=r;i=last+1){ 78 last=min(r/(r/i),l/i?(l/(l/i)):INF); 79 re+=(Mu_sum(last)-Mu_sum(i-1))*Pow(r/i-l/i,n); 80 re%=P; 81 } 82 return (re%P+P)%P; 83 } 84 int main(){ 85 #ifndef ONLINE_JUDGE 86 freopen("3930.in","r",stdin); 87 freopen("3930.out","w",stdout); 88 #endif 89 n=getint(); d=getint(); l=getint(); r=getint(); 90 l=(l-1)/d; r=r/d; 91 getmu(); 92 printf("%lld\n",solve()); 93 return 0; 94 }
然而$H-L \leq 10^5$并没用?不是的……我们可以枚举倍数!
Orz syk
记f[i]为gcd恰好为$K*i$的选数方案数,那么对于每一个$i$记$L$为$\lceil \frac{a}{K*i}\rceil $,$R$为$\lfloor\frac{b}{K*i}\rfloor$ 那么他的方案数就为$f[i] = (R-L+1) ^ N - (R-L+1)-\sum_{a=1,2,\dots} f[a*i]$最后的f[1]即为答案。注意若$\lceil \frac{a}{K} \rceil == 1$ 那么全部选K也是一种方案,需要+1。
(话说好不容易想到一次莫比乌斯反演,然而却做不出来……唉
1 /************************************************************** 2 Problem: 3930 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:412 ms 7 Memory:1664 kb 8 ****************************************************************/ 9 10 //BZOJ 3930 11 #include<cstdio> 12 #include<cstring> 13 #include<cstdlib> 14 #include<iostream> 15 #include<algorithm> 16 #define rep(i,n) for(int i=0;i<n;++i) 17 #define F(i,j,n) for(int i=j;i<=n;++i) 18 #define D(i,j,n) for(int i=j;i>=n;--i) 19 #define pb push_back 20 using namespace std; 21 typedef long long LL; 22 inline int getint(){ 23 int r=1,v=0; char ch=getchar(); 24 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 25 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 26 return r*v; 27 } 28 const int N=1e5+10,P=1e9+7; 29 /*******************template********************/ 30 31 int d[N],n,K,l,r,a,b; 32 int Pow(int a,int b){ 33 int r=1; 34 for(;b;b>>=1,a=(LL)a*a%P) if (b&1) r=(LL)r*a%P; 35 return r; 36 } 37 int main(){ 38 #ifndef ONLINE_JUDGE 39 freopen("3930.in","r",stdin); 40 freopen("3930.out","w",stdout); 41 #endif 42 n=getint(); K=getint(); a=getint(); b=getint(); 43 l=a/K; r=b/K; 44 if (a%K) l++; 45 D(i,100000,1){ 46 int R=r/i,L=l/i; 47 if (l%i) L++; 48 if (l<=r){ 49 d[i]=Pow(R-L+1,n); 50 d[i]=(d[i]-(R-L+1)+P)%P; 51 for(int j=i+i;j<=100000;j+=i) d[i]=(d[i]-d[j]+P)%P; 52 } 53 } 54 if (l==1) d[1]=(d[1]+1)%P; 55 printf("%d\n",d[1]); 56 return 0; 57 }
3930: [CQOI2015]选数
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 434 Solved: 222
[Submit][Status][Discuss]
Description
我 们知道,从区间[L,H](L和H为整数)中选取N个整数,总共有(H-L+1)^N种方案。小z很好奇这样选出的数的最大公约数的规律,他决定对每种方 案选出的N个整数都求一次最大公约数,以便进一步研究。然而他很快发现工作量太大了,于是向你寻求帮助。你的任务很简单,小z会告诉你一个整数K,你需要 回答他最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。
Input
输入一行,包含4个空格分开的正整数,依次为N,K,L和H。
Output
输出一个整数,为所求方案数。
Sample Input
2 2 2 4
Sample Output
3
HINT
样例解释
所有可能的选择方案:(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4), (4, 2), (4, 3), (4, 4)
其中最大公约数等于2的只有3组:(2, 2), (2, 4), (4, 2)
对于100%的数据,1≤N,K≤10^9,1≤L≤H≤10^9,H-L≤10^5