A - Playing with Paper: 问一个矩阵最多能被切成多少个正方形。暴力即可
#include #include #include #include #include #include #include #include #include #include #include using namespace std; #define lson l, mid, rt <<1 #define rson mid + 1, r, rt <<1 | 1 #define pi acos(-1.0) #define eps 1e-8 typedef long long ll; const int inf = 0x3f3f3f3f; ll n, m; int main() { while( cin >> n >> m ) { ll ans = 0; while( 1 ) { if( n % m == 0 ) { ans += n / m; break; } ans += n / m; n = n - n / m * m; swap( n, m ); } cout < B - Error Correct System :问两个长度相同的串通过交换随意的两个字符能不能使同样位置的不同字符的数尽可能少,输出交换后相同位置的不同的数,如果可以减少的话,输出使减少数量最大的两个位置 对不同的位置的两个字母建边,然后三重循环找答案 #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define lson l, mid, rt <<1 #define rson mid + 1, r, rt <<1 | 1 #define pi acos(-1.0) #define eps 1e-8 typedef long long ll; const int inf = 0x3f3f3f3f; const int N = 200010; char a[N], c[N]; int n; int mat[30][30]; int main() { while(~scanf("%d", &n)) { int cnt = 0; int p1, p2; memset( mat, -1, sizeof( mat ) ); scanf("%s %s", a, c); for( int i = 0; i 0 ) { if( mat[j][i] > 0 ) { printf("%d\n%d %d\n", cnt-2, mat[i][j], mat[j][i]); OK = 1; break; } if( OK ) continue; for( int k = 0; k <26; ++k ) { if( mat[j][k] > 0 && k != j ) { p1 = mat[i][j]; p2 = mat[j][k]; OK = 2; break; } } } } if( OK == 1 ) break; } if( !OK ) printf("%d\n-1 -1\n", cnt); else if( OK == 2 ) printf("%d\n%d %d\n", cnt-1, p1, p2); } return 0; } C - Glass Carving 问在切割一个矩阵的过程中,最大小矩阵的面积是多少 首先确定,若某一个子矩阵的面积最大,那么这个矩阵的长和宽在所有的矩阵中,长和宽必定是里面最大的。那么只需要记录和更新矩阵的长和宽即可。可知每次切割矩阵的时候,必定是将某段子长(宽)切成两块,那么删除这段长度,并且同时更新两段新切割出的长度即可,最后输出最大长和宽之积即可 #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define lson l, mid, rt <<1 #define rson mid + 1, r, rt <<1 | 1 #define pi acos(-1.0) #define eps 1e-8 typedef long long ll; const int inf = 0x3f3f3f3f; const int N = 200010; set v, h;//记录切割的点 set vv, hh;//记录长度 map V, H;//记录长度的数量 set :: iterator it, it1; map :: iterator mp1, mp2; int n, m, q; void init() { V.clear(); H.clear(); v.clear(); h.clear(); vv.clear(); hh.clear(); } int main() { while(~scanf("%d%d%d", &m, &n, &q)) { init(); v.insert(0); v.insert(m); h.insert(0); h.insert(n); V[m]++; H[n]++; hh.insert(n); vv.insert(m); while( q-- ) { char op[10]; int x; scanf("%s%d", op, &x); if( x == 0 ) continue; if( op[0] == 'H' ) { it1 = h.lower_bound(x); it = it1; it1--; //printf("between: %d %d\n", *it1, *it); h.insert(x); int xx = *it - *it1; //if( H.find( *it - *it1 ) != H.end() ) // H.erase( *it - *it1 ); //H.insert( (*it - x) ); //H.insert( (x - *it1) ); if( H[xx] ) H[xx]--; if( !H[xx] ) hh.erase(xx); H[ *it - x ]++; H[ x - *it1 ]++; if( hh.find( *it-x ) == hh.end() ) hh.insert( *it - x ); if( hh.find( x - *it1) == hh.end() ) hh.insert( x - *it1 ); } else { it1 = v.lower_bound(x); it = it1; it1--; //printf("between: %d %d\n", *it1, *it); v.insert(x); int xx = *it - *it1; //if( V.find( *it - *it1 ) != V.end() ) // V.erase( *it - *it1 ); //V.insert( (*it - x) ); //V.insert( (x - *it1) ); if( V[xx] ) V[xx]--; if( !V[xx] ) vv.erase(xx); V[ *it - x ]++; V[ x - *it1 ]++; if( vv.find( *it - x) == vv.end() ) vv.insert( *it - x ); if( vv.find( x - *it1) == vv.end() ) vv.insert( x - *it1); } ll ans = (ll) *hh.rbegin() * (ll) *vv.rbegin(); cout < D - Clique Problem 给出n个点,每点有两个信息,wi, xi,其中两点满足(x1 - x2) >= w1 + w2,则两点可以连边。问最大的某个集合里面点的数量(集合里面任意两点都可相互到达)。 将x看成坐标轴上点的圆心,w看成该圆的半径,那么条件就转换为,若是坐标轴上两个圆相切或是相离,则认为两个圆可以连边。那么先对所以点排序,根据w+r升序。然后遍历所有的点,每次若是ri - wi > cur(当前最右距离),res++;同时更新最右的cur。 #include using namespace std; const int N = 200010; struct node{ int x, r; }a[N]; int cmp( const node &q, const node &w) { return q.x + q.r = dis ){ ans++; dis = max( dis, a[i].r + a[i].x ); } } cout <
对不同的位置的两个字母建边,然后三重循环找答案
#include #include #include #include #include #include #include #include #include #include #include using namespace std; #define lson l, mid, rt <<1 #define rson mid + 1, r, rt <<1 | 1 #define pi acos(-1.0) #define eps 1e-8 typedef long long ll; const int inf = 0x3f3f3f3f; const int N = 200010; char a[N], c[N]; int n; int mat[30][30]; int main() { while(~scanf("%d", &n)) { int cnt = 0; int p1, p2; memset( mat, -1, sizeof( mat ) ); scanf("%s %s", a, c); for( int i = 0; i 0 ) { if( mat[j][i] > 0 ) { printf("%d\n%d %d\n", cnt-2, mat[i][j], mat[j][i]); OK = 1; break; } if( OK ) continue; for( int k = 0; k <26; ++k ) { if( mat[j][k] > 0 && k != j ) { p1 = mat[i][j]; p2 = mat[j][k]; OK = 2; break; } } } } if( OK == 1 ) break; } if( !OK ) printf("%d\n-1 -1\n", cnt); else if( OK == 2 ) printf("%d\n%d %d\n", cnt-1, p1, p2); } return 0; }
首先确定,若某一个子矩阵的面积最大,那么这个矩阵的长和宽在所有的矩阵中,长和宽必定是里面最大的。那么只需要记录和更新矩阵的长和宽即可。可知每次切割矩阵的时候,必定是将某段子长(宽)切成两块,那么删除这段长度,并且同时更新两段新切割出的长度即可,最后输出最大长和宽之积即可
#include #include #include #include #include #include #include #include #include #include #include using namespace std; #define lson l, mid, rt <<1 #define rson mid + 1, r, rt <<1 | 1 #define pi acos(-1.0) #define eps 1e-8 typedef long long ll; const int inf = 0x3f3f3f3f; const int N = 200010; set v, h;//记录切割的点 set vv, hh;//记录长度 map V, H;//记录长度的数量 set :: iterator it, it1; map :: iterator mp1, mp2; int n, m, q; void init() { V.clear(); H.clear(); v.clear(); h.clear(); vv.clear(); hh.clear(); } int main() { while(~scanf("%d%d%d", &m, &n, &q)) { init(); v.insert(0); v.insert(m); h.insert(0); h.insert(n); V[m]++; H[n]++; hh.insert(n); vv.insert(m); while( q-- ) { char op[10]; int x; scanf("%s%d", op, &x); if( x == 0 ) continue; if( op[0] == 'H' ) { it1 = h.lower_bound(x); it = it1; it1--; //printf("between: %d %d\n", *it1, *it); h.insert(x); int xx = *it - *it1; //if( H.find( *it - *it1 ) != H.end() ) // H.erase( *it - *it1 ); //H.insert( (*it - x) ); //H.insert( (x - *it1) ); if( H[xx] ) H[xx]--; if( !H[xx] ) hh.erase(xx); H[ *it - x ]++; H[ x - *it1 ]++; if( hh.find( *it-x ) == hh.end() ) hh.insert( *it - x ); if( hh.find( x - *it1) == hh.end() ) hh.insert( x - *it1 ); } else { it1 = v.lower_bound(x); it = it1; it1--; //printf("between: %d %d\n", *it1, *it); v.insert(x); int xx = *it - *it1; //if( V.find( *it - *it1 ) != V.end() ) // V.erase( *it - *it1 ); //V.insert( (*it - x) ); //V.insert( (x - *it1) ); if( V[xx] ) V[xx]--; if( !V[xx] ) vv.erase(xx); V[ *it - x ]++; V[ x - *it1 ]++; if( vv.find( *it - x) == vv.end() ) vv.insert( *it - x ); if( vv.find( x - *it1) == vv.end() ) vv.insert( x - *it1); } ll ans = (ll) *hh.rbegin() * (ll) *vv.rbegin(); cout < D - Clique Problem 给出n个点,每点有两个信息,wi, xi,其中两点满足(x1 - x2) >= w1 + w2,则两点可以连边。问最大的某个集合里面点的数量(集合里面任意两点都可相互到达)。 将x看成坐标轴上点的圆心,w看成该圆的半径,那么条件就转换为,若是坐标轴上两个圆相切或是相离,则认为两个圆可以连边。那么先对所以点排序,根据w+r升序。然后遍历所有的点,每次若是ri - wi > cur(当前最右距离),res++;同时更新最右的cur。 #include using namespace std; const int N = 200010; struct node{ int x, r; }a[N]; int cmp( const node &q, const node &w) { return q.x + q.r = dis ){ ans++; dis = max( dis, a[i].r + a[i].x ); } } cout <
将x看成坐标轴上点的圆心,w看成该圆的半径,那么条件就转换为,若是坐标轴上两个圆相切或是相离,则认为两个圆可以连边。那么先对所以点排序,根据w+r升序。然后遍历所有的点,每次若是ri - wi > cur(当前最右距离),res++;同时更新最右的cur。
#include using namespace std; const int N = 200010; struct node{ int x, r; }a[N]; int cmp( const node &q, const node &w) { return q.x + q.r = dis ){ ans++; dis = max( dis, a[i].r + a[i].x ); } } cout <