题解
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn= 4e5 + 10 ;
int n, m, a[ maxn] , num[ maxn] , tot= 0 , sum[ maxn] ;
int solve ( int k)
{
return ( int ) ceil ( log2 ( ( double ) k) ) ;
}
int main ( )
{
scanf ( "%d %d" , & n, & m) ;
for ( int i= 1 ; i<= n; i++ ) scanf ( "%d" , & a[ i] ) ;
sort ( a+ 1 , a+ n+ 1 ) ; int last= 0 ;
for ( int i= 1 ; i<= n; i++ ) if ( i!= 1 && a[ i] != a[ i- 1 ] ) num[ ++ tot] = i- 1 - last, last= i- 1 ;
num[ ++ tot] = n- last;
for ( int i= 1 ; i<= tot; i++ ) sum[ i] = sum[ i- 1 ] + num[ i] ;
int l= 1 , r= 0 ; int ans= 0x3f3f3f3f ;
while ( l<= tot|| r<= tot) {
while ( r<= tot&& solve ( r- l+ 1 ) * n<= 8 * m) r++ ;
if ( solve ( r- l) * n<= 8 * m) ans= min ( ans, n- sum[ r- 1 ] + sum[ l- 1 ] ) ;
l++ ;
}
printf ( "%d\n" , ans) ;
}
题意
就是给你一个数组,两种操作,第一种是修改某个位置的值,另一种是将当前数组中所有小于
x
x
x 的数改成
x
x
x
题解
首先对于每一个
1
1
1 操作,考虑他后面所有的
2
2
2 操作的最大
x
x
x 值,与当前该位置值取
m
a
x
max
m a x 后就是它这个位置最后的值,最后遍历整个数组,如果某个位置没有被
1
1
1 操作过,那么这个位置与最大的
x
x
x 取
m
a
x
max
m a x 就是最后该位置的值
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn= 2e5 + 10 ;
int n, a[ maxn] , maxx[ maxn] , opt[ maxn] , c[ maxn] [ 2 ] , b[ maxn] , flag[ maxn] ;
int main ( )
{
scanf ( "%d" , & n) ;
for ( int i= 1 ; i<= n; i++ ) scanf ( "%d" , & a[ i] ) ;
int q; scanf ( "%d" , & q) ;
for ( int i= 1 ; i<= q; i++ ) {
scanf ( "%d" , & opt[ i] ) ;
if ( opt[ i] == 1 ) {
scanf ( "%d %d" , & c[ i] [ 0 ] , & c[ i] [ 1 ] ) ;
flag[ c[ i] [ 0 ] ] = 1 ;
} else {
scanf ( "%d" , & b[ i] ) ;
}
}
memset ( maxx, - 1 , sizeof ( maxx) ) ;
for ( int i= q; i>= 1 ; i-- ) {
if ( opt[ i] == 2 ) {
maxx[ i] = max ( b[ i] , maxx[ i+ 1 ] ) ;
} else maxx[ i] = maxx[ i+ 1 ] ;
}
for ( int i= 1 ; i<= q; i++ ) {
if ( opt[ i] == 1 ) {
a[ c[ i] [ 0 ] ] = c[ i] [ 1 ] ;
if ( maxx[ i+ 1 ] > a[ c[ i] [ 0 ] ] ) {
a[ c[ i] [ 0 ] ] = maxx[ i+ 1 ] ;
}
}
}
int opt2= - 1 ;
for ( int i= 1 ; i<= q; i++ ) if ( opt[ i] == 2 && b[ i] > opt2) opt2= b[ i] ;
for ( int i= 1 ; i<= n; i++ ) if ( ! flag[ i] && a[ i] < opt2) a[ i] = opt2;
for ( int i= 1 ; i<= n; i++ ) printf ( "%d%c" , a[ i] , i== n? '\n' : ' ' ) ;
}
题意
就是给你一个含有
3
×
n
3\times n
3 × n 个节点,
m
m
m 条边构成的图,求一个含有
n
n
n 条边的匹配或者
n
n
n 个节点的独立集,两者都不存在的话输出
I
m
p
o
s
s
i
b
l
e
Impossible
I m p o s s i b l e
题解
至于为什么是
3
×
n
3\times n
3 × n 个节点呢?咱也不知道
233
233
2 3 3 考虑从任意一条边找到一个匹配,能加边就加,那么最后剩下的点的状态就是任意两个点之间没有边相连,如果找到了大小为
n
n
n 的匹配,直接返回,否则可以根据找匹配过程后未使用的节点中的任意
n
n
n 个即为独立集,而且显然一定能找到这样的独立集,因为如果没有
n
n
n 条匹配的边,那么用过的点数
<
2
×
n
<2\times n
< 2 × n ,也就说明能找到大于
n
n
n 个点的独立集 所以说没必要取找一个最大的匹配,显然答案一定有解
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn= 3e5 + 10 ;
const int maxm= 5e5 + 10 ;
int x[ maxm] , y[ maxm] , vis[ maxn] , n, m;
int edge[ maxm] , tot1, node[ maxn] , tot2;
bool work1 ( )
{
tot1= tot2= 0 ;
for ( int i= 1 ; i<= 3 * n; i++ ) vis[ i] = 0 ;
for ( int i= 1 ; i<= m; i++ ) if ( ! vis[ x[ i] ] && ! vis[ y[ i] ] ) {
vis[ x[ i] ] = vis[ y[ i] ] = 1 ;
edge[ ++ tot1] = i;
}
if ( tot1>= n) {
printf ( "Matching\n" ) ;
for ( int i= 1 ; i<= n; i++ ) printf ( "%d%c" , edge[ i] , i== n? '\n' : ' ' ) ;
return true;
}
return false;
}
bool work2 ( )
{
for ( int i= 1 ; i<= 3 * n; i++ ) if ( ! vis[ i] ) node[ ++ tot2] = i;
if ( tot2>= n) {
printf ( "IndSet\n" ) ;
for ( int i= 1 ; i<= n; i++ ) printf ( "%d%c" , node[ i] , i== n? '\n' : ' ' ) ;
return true;
}
return false;
}
int main ( )
{
int t; scanf ( "%d" , & t) ;
while ( t-- ) {
scanf ( "%d %d" , & n, & m) ;
for ( int i= 1 ; i<= m; i++ ) scanf ( "%d %d" , & x[ i] , & y[ i] ) ;
if ( ! work1 ( ) && ! work2 ( ) ) printf ( "Impossible\n" ) ;
}
}
题意
给你一个
n
×
n
n \times n
n × n 的矩阵,每个位置为黑或者白,每次可以选一个
h
×
w
h\times w
h × w 的子矩阵并将其内所有位置涂白,对应的代价为
m
a
x
(
h
,
w
)
max(h,w)
m a x ( h , w ) ,求将这个矩阵全部涂白的最小代价
题解
d
p
dp
d p 考虑将当前矩阵上下分成两半或者左右分成两半进行转移
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn= 55 ;
int n, dp[ maxn] [ maxn] [ maxn] [ maxn] ;
char s[ maxn] [ maxn] ;
int main ( )
{
scanf ( "%d" , & n) ;
for ( int i= 1 ; i<= n; i++ ) scanf ( "%s" , s[ i] + 1 ) ;
for ( int h= 1 ; h<= n; h++ ) {
for ( int w= 1 ; w<= n; w++ ) {
for ( int i= 1 ; i+ h- 1 <= n; i++ ) {
for ( int j= 1 ; j+ w- 1 <= n; j++ ) {
if ( w== 1 && h== 1 ) { dp[ i] [ j] [ h] [ w] = ( s[ i] [ j] == '#' ) ; continue ; }
dp[ i] [ j] [ h] [ w] = max ( h, w) ;
for ( int k= 1 ; k< h; k++ ) dp[ i] [ j] [ h] [ w] = min ( dp[ i] [ j] [ h] [ w] , dp[ i] [ j] [ k] [ w] + dp[ i+ k] [ j] [ h- k] [ w] ) ;
for ( int k= 1 ; k< w; k++ ) dp[ i] [ j] [ h] [ w] = min ( dp[ i] [ j] [ h] [ w] , dp[ i] [ j] [ h] [ k] + dp[ i] [ j+ k] [ h] [ w- k] ) ;
}
}
}
}
printf ( "%d\n" , dp[ 1 ] [ 1 ] [ n] [ n] ) ;
}