题意:
给出两个数N,M。让你求数列(和为M,gcd为N)的个数。
题解:
首先,比较容易发现的是M%N如果不为零,那么一定不能构成这样的序列。那么可以设 k = M/N,则可以想象为用k个1来构成序列的个数,运用隔板原理可以求出k个1可以构成的序列总数为2^(k-1),但是这里面其实有不构成条件的(gcd>N)比方说6个相同的数(2,2,2)构成这样gcd就是2×N而不是N了。所以要减去这些数的情况,这样减的话发现不能用递归来做,要先记忆化。记忆化因为这里面最大的数是1e9不能用数组储存,要用map离散。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX_N=1e5+5; 4 const int MOD = 1e9+7; 5 map<long long , long long > mp; 6 long long quick_pow(int x) 7 { 8 x -= 1; 9 long long base = 2; 10 long long ans = 1; 11 while(x) 12 { 13 if(x&1) ans = (ans * base)%MOD; 14 x >>= 1; 15 base = (base*base)%MOD; 16 } 17 return ans; 18 } 19 long long solve(int x) 20 { 21 if(mp.count(x)) return mp[x]; 22 long long ans = quick_pow(x)-1; 23 for(int i=2;i*i<=x;i++) 24 { 25 if(x%i == 0) 26 { 27 ans = (ans - solve(i) + MOD)%MOD; 28 if(x/i != i) 29 { 30 ans = (ans - solve(x/i) + MOD)%MOD; 31 } 32 } 33 } 34 mp.insert(make_pair(x,ans)); 35 return ans; 36 } 37 int main() 38 { 39 long long N,M,T; 40 mp.insert(make_pair(1,1)); 41 while(cin>>N>>M) 42 { 43 if(M%N != 0) 44 { 45 printf("0\n"); 46 } 47 else 48 { 49 printf("%lld\n",solve(M/N)); 50 } 51 } 52 return 0; 53 }