【欧拉函数】
大致题意:如果知道f(a, b),就可以求出f(a * k, b * k)。现给出一个n,求至少需要知道几个二元组(a, b),使所有的f(x, y)都能求出来。(1 <= x, y <= n)
首先能确定的是gcd(a, b) = 1。不妨假设b >= a,那么如果b一定,至少需要phi(b)个a,才能知道所有的f(a * k, b * k)。令dp[n]表示这种情况下的答案,则dp[n] = ∑phi[i] (1 <= i <= n)。
上述是在a <= b的条件下得出的,如果没有这个条件,那么dp'[n] = dp[n] * 2 - 1。因为对于f(1, 1)只用求一遍。
总结一下,O(nlogn)预处理欧拉函数(当然线性的更好了)和前缀和,然后O(1)询问。
1 #include2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 using namespace std;12 #define enter puts("")13 #define space putchar(' ')14 #define Mem(a, x) memset(a, x, sizeof(a))15 #define rg register16 typedef long long ll;17 typedef double db;18 const int INF = 0x3f3f3f3f;19 const db eps = 1e-8;20 const int maxn = 5e4 + 5;21 inline ll read()22 {23 ll ans = 0;24 char ch = getchar(), las = ' ';25 while(!isdigit(ch)) las = ch, ch = getchar();26 while(isdigit(ch)) ans = ans * 10 + ch - '0', ch = getchar();27 if(las == '-') ans = -ans;28 return ans;29 }30 inline void write(ll x)31 {32 if(x < 0) putchar('-'), x = -x;33 if(x >= 10) write(x / 10);34 putchar(x % 10 + '0');35 }36 37 int n, phi[maxn], sum[maxn];38 39 void euler()40 {41 for(int i = 1; i < maxn; ++i) phi[i] = i;42 for(int i = 2; i < maxn; ++i) if(phi[i] == i)43 for(int j = i; j < maxn; j += i)44 phi[j] = phi[j] / i * (i - 1);45 for(int i = 1; i < maxn; ++i) sum[i] = sum[i - 1] + phi[i];46 }47 48 int main()49 {50 euler();51 while(scanf("%d", &n) && n)52 write((sum[n] << 1) - 1), enter;53 return 0;54 }