AtCoder Beginner Contest 229

A - First Grid

\(2\times 2\)矩阵只有两种情况不满足

.#	#.
#.	.#

特判即可

如果一个#相邻的三个格子全是.则一定不可能联通

#include<bits/stdc++.h>
using namespace std;
int main(){
  string s1,s2;
  cin >> s1 >> s2;
  if(s1=="#." && s2==".#"){cout << "No\n";}
  else if(s1==".#" && s2=="#."){cout << "No\n";}
  else{cout << "Yes\n";}
  return 0;
}

B - Hard Calculation

判断a+b的过程中是否进位

判断是否有一位相加大于9即可

#include<bits/stdc++.h>
using namespace std;

int main()
{
    long long a , b , x , y ;
    cin >> a >> b;
    while( a && b )
    {
        x = a % 10 , y = b % 10 , a /= 10 , b /= 10;
        if( x + y >= 10 )
        {
            cout << "Hard\n";
            return 0;
        }
    }
    cout << "Easy\n";
    return 0;
}

C - Cheese

\(N\)中奶酪,每种奶酪的美味值是\(A_i\)每克,每种奶酪有\(B_i\)克,最多选择\(W\)克,问美味值最大是多少

贪心选择美味值高的

#include<bits/stdc++.h>
using namespace std;
#define a first
#define b second
long long n , w , res ;
vector< pair< long long , long long > > p;


int main()
{
    cin >> n >> w ;
    for( int i = 1 , x , y ; i <= n ; i ++ ) cin >> x >> y , p.push_back( { x , y } );
    sort( p.begin() , p.end() , greater< pair< int ,int > >() );
    for( int i = 0 ; i < n && w ; i ++ )
    {
        if( p[i].b <= w ) res += p[i].a * p[i].b , w -= p[i].b;
        else res += p[i].a * w , w = 0;
    }
    cout << res << endl;
}

D - Longest X

给一个字符串\(S\)只由X.组成,共有\(K\)次操作,每次可以任意把一个.换成x,不一定要用完\(K\)次操作,问操作做后最长的连续\(X\)有多长

前缀和统计[1,i]有多少个.,这样可以\(O(1)\)求解任意区间内.的数量

二分答案,暴力的枚举区间的端点,判断区间内.的个数是否小于\(K\)

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;
int n , a[N] , k , res;
string s;

bool check( int len )
{
    for( int i = len ; i <= n ; i ++ )
    {
        if( a[i] - a[ i - len ] <= k ) return 1;
    }
    return 0;
}

int main()
{
    cin >> s >> k;
    n = s.size();
    for( int i = 1 ; i <= n ; i ++ ) a[i] = a[i-1] + ( s[ i - 1 ] == 'X' ? 0 : 1 );
    int l = 1 , r = n , mid;
    while( l <= r )
    {
        mid = ( l + r ) >> 1;
        if( check(mid) ) res = mid , l = mid + 1;
        else r = mid - 1;
    }
    cout << res << endl;
    return 0;
}

E - Graph Destruction

给一个图\(N\)个点、\(M\)条边。每条边连接\(A_i\)\(B_i\)。会一个接一个的删除\(1,2,\cdots,N\)点。删除点\(i\)意味着从图中删除点和他所连的所有边。问每次删除点后,图中有多少给联通块。

倒叙枚举,每次加点,加点的过程中加边,用并查集来维护连通块。

加边的时候两个端点不一定同时存在在图中,所以存边的时候保证\(A_i<B_i\)这样在加\(A_i\)所连的边时\(B_i\)一定在图中。

并查集维护时,如果边的两个端点属于不同的连通块,加边后连通块数量就会减一。

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 5;
int n , m , res[N] , fa[N];
vector< int > e[N];

int getfa( int x )
{
    if( fa[x] == x ) return x;
    return fa[x] = getfa( fa[x] );
}

bool merge( int x , int y )
{
    int fx = getfa( x ) , fy = getfa(y);
    if( fx == fy ) return 0;
    fa[fx] = fy;
    return 1;
}

int main()
{
    cin >> n >> m;
    for( int i = 1 ; i <= n ; i ++ ) fa[i] = i;
    for( int i = 1 , x , y ; i <= m ; i ++ )
    {
        cin >> x >> y;
        if( x > y ) e[y].push_back(x);
        else e[x].push_back(y);
    }
    for( int i = n - 1 ; i >= 1 ; i -- )
    {
        res[i] = res[ i + 1 ] + 1;
        for( auto v : e[ i + 1 ] ) if( merge( v , i + 1 ) ) res[i]--;
    }
    for( int i = 1 ; i <= n ; i ++ ) cout << res[i] << endl;
    return 0;
}
posted @ 2021-11-28 20:08  PHarr  阅读(229)  评论(0编辑  收藏  举报