CF上的题一向都是非常灵活的,很注重想法,而不是依赖固定的算法。
今天做了一道,虽然只是C难度的题,但是也还是做了将近3个小时。
说说题吧。
题目就是说有n个数,每两个数分成一堆,条件是这两个数GCD不能小于2.问最多可以分多少堆。
我刚开始就想,要先求出素数,然后根据每个素数分成几份,从最大的数开始,依次找到2,其中以前分过的数不可以再分。如果一份数的个数是奇数,就把一个偶数踢出去。最后在计算每一份有多少对,然后相加。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> using namespace std; const int maxn = 100010; int v[maxn]; int prim[maxn]; int num, sum[maxn]; void prime(int n) { num = 0; memset(v, 0, sizeof(v)); for(int i = 2; i <= n; i++) if(!v[i]) { v[i] = 1; sum[num] = n / i; prim[num++] = i; for(int j = i * 2; j <= n; j += i) v[j] = 1; } } int main() { int n; while(cin >> n) { int ans = 0; int used2 = 0; num = 0; prime(n); memset(v, 0, sizeof(v)); for(int i = num - 1; i >= 0; i--) { int t = 0; for(int j = 1; j <= sum[i]; j++) if(!v[j * prim[i]]) { t++; v[j * prim[i]] = prim[i]; //cout << j * prim[i] << " " << prim[i] << " "; } // cout << t << endl; ans += t / 2; if(t % 2 && t > 1) { v[2 * prim[i]] = 0; } /*for(int i = 2; i <= n; i++) cout << v[i] << " "; cout << endl << endl;*/ } printf("%d ", ans); for(int i = num - 1; i >= 0; i--) { int sum1 = 0; for(int k = prim[i]; k <= n; k += prim[i]) if(v[k] == prim[i]) if(!sum1) { sum1 = k; } else { printf("%d %d ", sum1, k); sum1 = 0; } } } }