Codeforces 900D Unusual Sequences:記憶化搜尋

Leohh發表於2018-02-24

題目連結: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 }

 

相關文章