CF1622F Quadratic Set

观察到答案的下界\(n-3\)

证明:
\(n\) 为偶数,令 \(k=\frac{n}{2}\)
\(\displaystyle \prod_{i=1}^{2k} i!=\left(\prod_{i=1}^k (2i-1)! \right)^22^kk!\)

  • \(k\) 为偶数时,删去 \(k\) 即可
  • \(k\) 为奇数时,删去 \(2,k\) 即可

\(n\) 为奇数,删去 \(n\) 转化为偶数的情况,最多删去 \(3\) 个数。

注意上述构造不一定是最优的,需要依次判断。


最后一个问题,如何快速判断一个数是否为完全平方数?

考虑异或哈希,将每一个质数 \(p\) 随机赋权 \(f(p)\) ,并规定 \(f(1)=0,f(ab)=f(a) \oplus f(b)\)

那么 \(x\) 为完全平方数 \(\Leftrightarrow\) \(f(x)=0\)

#include <bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define pii pair< int , int >
#define fi first
#define sc second
#define mp make_pair

ull rd( ) {
    return ( rand() + 0llu ) | ( ( rand() + 0llu ) << 16llu ) | ( ( rand() + 0llu ) << 32llu ) | ( ( rand() + 0llu ) << 48llu );
}

const int MAXN = 1e6;
int prn , pri[ MAXN + 5 ]; bool vis[ MAXN + 5 ];
ull f[ MAXN + 5 ];
void sieve() {
    f[ 1 ] = 0;
    for( int i = 2 ; i <= MAXN ; i ++ ) {
        if( !vis[ i ] ) pri[ ++ prn ] = i , f[ i ] = rd();
        for( int j = 1 ; j <= prn && 1ll * i * pri[ j ] <= MAXN ; j ++ ) {
            vis[ i * pri[ j ] ] = 1;
            f[ i * pri[ j ] ] = f[ i ] ^ f[ pri[ j ] ];
            if( i % pri[ j ] == 0 ) break;
        }
    }
    for( int i = 1 ; i <= MAXN ; i ++ ) f[ i ] ^= f[ i - 1 ];
}

int n; ull hs;
unordered_map< ull , int > vish;
int main( ) {
    srand( 123456 ); sieve();
    scanf("%d",&n);

    //n
    for( int i = 1 ; i <= n ; i ++ ) hs ^= f[ i ];
    if( hs == 0 ) {
        printf("%d\n", n );
        for( int i = 1 ; i <= n ; i ++ ) printf("%d ", i );
        return 0;
    }

    //n-1
    for( int i = 1 ; i <= n ; i ++ ) if( ( hs ^ f[ i ] ) == 0 ) {
        printf("%d\n", n - 1 );
        for( int j = 1 ; j <= n ; j ++ ) if( i != j ) printf("%d ", j );
        return 0;
    }

    //n-2
    for( int i = 1 ; i <= n ; i ++ ) {
        if( vish[ f[ i ] ] ) {
            printf("%d\n", n - 2 );
            for( int j = 1 ; j <= n ; j ++ ) if( j != i && j != vish[ f[ i ] ] ) printf("%d ", j );
            return 0;
        }
        vish[ hs ^ f[ i ] ] = i;
    }

    //n-3
    assert( n & 1 );
    printf("%d\n", n - 3 );
    for( int i = 1 ; i <= n ; i ++ ) if( i != 2 && i != ( n - 1 ) / 2 && i != n ) printf("%d ", i );
    return 0;
}
posted @ 2022-10-29 09:16  chihik  阅读(92)  评论(0编辑  收藏  举报