题目链接:
题目大意:
对1~n的自然数构成数对,每个数对中的两个数不互质,问最多能得到多少组数对。
题目分析:
- 对于每个大于2的素数,我们枚举它的倍数,得到个数,如果的得到的个数是奇数,我们可以通过舍去2*p这个数,得到正好偶数个,正好凑出数对,这样的方案一定是最优的。因为没有造成浪费。
- 然后剩下2的倍数的数再进行组合,得到的就是最优解。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#define MAX 100007
using namespace std;
typedef pair<int,int> PII;
int n;
int mark[MAX];
vector<int> prime;
vector<PII> pp;
stack<int> temp;
void init ( )
{
prime.clear();
memset ( mark , -1 , sizeof ( mark ) );
for ( int i = 2 ; i < MAX ; i++ )
{
if ( ~mark[i] ) continue;
prime.push_back ( i );
for ( int j = 2*i ; j < MAX ; j += i )
mark[j] = i;
}
}
int main ( )
{
init ( );
while ( ~scanf ( "%d" , &n ) )
{
memset ( mark , 0 , sizeof ( mark ) );
int ans = 0;
pp.clear();
for ( int i = 1 ; i < prime.size() ; i++ )
{
int x = prime[i];
if ( x > n ) break;
while ( !temp.empty() ) temp.pop();
int num = 1;
mark[x] = 1;
temp.push ( x );
for ( int j = 3*x ; j <=n ; j+= x )
{
if ( mark[j] ) continue;
mark[j] = 1;
temp.push ( j );
num++;
}
if ( num&1 && 2*x <= n )
{
temp.push ( 2*x );
mark[2*x] = 1;
}
while ( temp.size() > 1 )
{
int a = temp.top();
temp.pop();
int b = temp.top();
temp.pop();
pp.push_back ( make_pair ( a , b ) );
}
}
while ( !temp.empty() ) temp.pop();
int num = 0;
for ( int i = 2 ; i <= n ; i += 2 )
{
if ( mark[i] ) continue;
temp.push ( i );
mark[i] = 1;
}
while ( temp.size() > 1 )
{
int a = temp.top();
temp.pop();
int b = temp.top();
temp.pop();
pp.push_back ( make_pair ( a , b ) );
}
printf ( "%d\n" , pp.size() );
for ( int i = 0 ; i < pp.size() ; i++ )
printf ( "%d %d\n" , pp[i].first , pp[i].second );
}
}