Codeforces 900D Unusual Sequences:记忆化搜索

题目链接:http://codeforces.com/problemset/problem/900/D

题意:

  给定x,y,问你有多少个数列a满足gcd(a[i]) = x 且 ∑(a[i]) = y。

题解:

  由于gcd(a[i]) = x,所以y一定是x的倍数,否则无解。

  那么原题就等价于:问你有多少个数列a满足gcd(a[i]) = 1 且 ∑(a[i]) = y/x。

 

  设f(k)为gcd(a[i]) = 1 且 ∑(a[i]) = k时的答案。

  只满足条件∑(a[i]) = k的数列共有2^(k-1)种(隔板法)

  然后要从中去掉gcd不为1的数列。

  每个和为k且gcd不为1的数列a1,对应着一个和为k的因数且gcd为1的数列a2。

  因为a1可以由a2整体放大而来。

  那么也就是f(k) = 2^(k-1) - ∑ f(p),其中p为k的因数(p != k)。

  搜索 + map记忆化即可。

 

  由于需要用到的f(k),k均为y/x的因数,最多sqrt(y/x)个。

  加上map的log复杂度,所以总复杂度为O(sqrt(n)*log(n))。

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <map>
 5 #define MOD 1000000007
 6 
 7 using namespace std;
 8 
 9 int x,y;
10 map<int,int> mp;
11 
12 long long quick_pow(long long n,long long k)
13 {
14     long long ans=1;
15     while(k>0)
16     {
17         if(k&1) ans=(ans*n)%MOD;
18         n=n*n%MOD;
19         k>>=1;
20     }
21     return ans;
22 }
23 
24 long long dfs(int i)
25 {
26     if(i==1) return 1;
27     if(mp.count(i)) return mp[i];
28     long long ans=quick_pow(2,i-1);
29     for(int j=2;j*j<=i;j++)
30     {
31         if(i%j==0)
32         {
33             ans=((ans-dfs(j))%MOD+MOD)%MOD;
34             if(i/j!=j) ans=((ans-dfs(i/j))%MOD+MOD)%MOD;
35         }
36     }
37     ans=((ans-1)%MOD+MOD)%MOD;
38     return mp[i]=ans;
39 }
40 
41 int main()
42 {
43     cin>>x>>y;
44     cout<<(y%x==0 ? dfs(y/x) : 0)<<endl;
45 }
原文地址:https://www.cnblogs.com/Leohh/p/8464069.html