分组
\(k=1\)的时候不难,暴力\(32\),转化一下记录和他对立的数之前有没有就有\(40\)了。
不过有一个小技巧需要记录一下:
当要找字典序最小的\(ans\)的时候,而我们只能找到字典序最大的\(ans\),可以考虑把序列反过来跑。
\(k=2\)就比较难受了。
因为我们可以容忍一个组里面出现对立的,朴素的出现对立就重分一组肯定是不行的(不过如果你打出来也有\(70^+pts\)的好成绩)
因为我们需要满足的原则是尽量把对立的都扔到不同的组里面。
搞一个扩展域的并查集,把每一点拆成了两个点,记为\(0\)号点和\(1\)号点。
还是用\(k=1\)的思路来记录
如果之前有对立的数,把第一个点的\(0\)和第二个点的\(1\)放到一个并查集里面,把第一个点的\(1\)和第二个点的\(0\)放到一个里面
如果我们发现并查集里面有同一个节点的\(0\)和\(1\),那就说明需要重新分一组了。
特判一下两个点相同的情况即可。
本人还是太菜了,这就是一个扩展域的并查集而已,但是本人却想不到。
code
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#define mp make_pair
#define R register int
#define int long
#define printf Ruusupuu = printf
int Ruusupuu ;
using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
typedef pair< int , int > PI ;
const int N = 3e5 + 10 ;
const int M = 131073 ;
inline int read(){
int w = 0 ; bool fg = 0 ; char ch = getchar() ;
while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ '0' ) , ch = getchar() ;
return fg ? -w : w ;
}
inline void wap( int &a , int &b ){ a = a ^ b , b = a ^ b , a = a ^ b ; }
inline int mins( int a , int b ){ int zt = b - a ; return a + ( zt & ( zt >> 31 ) ) ; }
inline int maxs( int a , int b ){ int zt = b - a ; return b - ( zt & ( zt >> 31 ) ) ; }
inline int abss( int a ){ int zt = a >> 31 ; return ( a + zt ) ^ zt ; }
int n , k , st [N] , top , fen [N] , pot , a [N] ;
int fa [N << 1] , fg [N] ; bool fgg [N] ;
inline bool pd( int x ){ int y = sqrt( x ) ; if( y * y == x ) return 1 ; else return 0 ; }
void sc(){
n = read() , k = read() ;
for( R i = 1 ; i <= n ; i ++ ) a [i] = read() ;
// printf( "%ld %ld %ld %ld\n" , a [912] , a [913] , a [914] , a [915] ) ;
}
void kqo(){
for( R i = n ; i >= 1 ; i -- ){
bool vis = 0 ;
for( R j = 2 ; j <= 512 ; j ++ )
if( j * j >= a [i] && fgg [j * j - a [i]] ) { fen [++ pot] = i ; memset( fgg , 0 , sizeof( fgg ) ) ; fgg [a [i]] = 1 ; vis = 1 ; break ; }
if( !vis ) fgg [a [i]] = 1 ;
} printf( "%ld\n" , pot + 1 ) ;
for( R i = pot ; i >= 1 ; i -- ) printf( "%ld " , fen [i] ) ;
}
inline int fd( int x ){
if( x == fa [x] ) return x ;
else return fa [x] = fd( fa [x] ) ;
}
inline void bk(){
for( R i = 1 ; i <= 2 * M ; i ++ ) fa [i] = i ;
}
inline bool spj( int x ){
for( R i = 2 ; i <= 512 ; i ++ )
if( i * i >= x && i * i != 2 * x && fg [i * i - x] ) return 0 ;
return 1 ;
}
void kqt(){
bk() ;
for( R i = n ; i >= 1 ; i -- ){
// printf( "%ld\n" , i ) ;
bool vis = 0 ;
for( R j = 2 ; j <= 512 ; j ++ ) if( j * j >= a [i] && fg [j * j - a [i]] ) {
fa [fd( a [i] + M )] = fd( j * j - a [i] ) ;
fa [fd( a [i] )] = fd( j * j - a [i] + M ) ;
if( fd( a [i] ) == fd( a [i] + M ) ){
if( a [i] == j * j - a [i] && fg [a [i]] == 1 && spj( a [i] ) ) break ;
else {
fen [++ pot] = i ;
memset( fg , 0 , sizeof( fg ) ) ; bk() ;
break ;
}
}
} if( !vis ) fg [a [i]] ++ ;
}
printf( "%ld\n" , pot + 1 ) ;
for( R i = pot ; i >= 1 ; i -- ) printf( "%ld " , fen [i] ) ;
}
void work(){
if( k == 1 ) kqo() ;
else kqt() ;
}
signed main(){
sc() ;
work() ;
return 0 ;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号