1. 程式人生 > 其它 >CF 790 Div.4完整題解

CF 790 Div.4完整題解

A. Lucky?

給n 個長度6 的數,問前三位和後三位中0 的數量是否相同

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

string s;

int main(){
    int t = read();
    while( t -- ){
       cin >> s;
       int a = 0 , b = 0;
       for( int i = 0 ; i < 3 ; i ++ )
            a += s[i] - '0';
       for( int i = 3 ; i < 6 ; i ++ )
           b += s[i] - '0';
       if( a == b )
           printf("YES\n");
       else
           printf("NO\n");
    }
    return 0;
}

B. Equal Candies

有 n 個盒子每個盒子裡面有\(a_i\)個糖果,可以吃掉任何一個盒子的任意數量個糖果,問最少吃掉多少糖果能使所有盒子糖果數量相同

找到糖果最少的盒子,其他盒子都變成這個數量就行

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

string s;

int lcm(  int x , int y ){
    return x * y / __gcd( x , y ) ;

}

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}
const int N = 55;

int a[N] , n , m ;
ll sum;

void solve(){
    n = read() , m = 1e9 , sum = 0;
    for( int i = 1 ; i <= n ; i ++ )
        a[i] = read() , m = min( a[i] , m );
    for( int i = 1 ; i <= n ; i ++ )
        sum += a[i] - m;
    cout << sum << endl;

}

int main(){
    int t = read();
    while( t -- )
        solve();
    return 0;
}

C. Most Similar Words

給 n 個長度是 m 的字串,從中選出兩個兩個字串的差最小是多少

因為資料很小直接列舉一下就行,\(O(n^2m)\)

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

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}
const int N = 55;

int n , m , sum , res;
string s[N];

void solve(){
    n = read() , m = read();
    for( int i = 1 ; i <= n ; i ++ )
        cin >> s[i];
    res = 1e9;
    for( int i = 1 ; i < n ; i ++ )
        for( int j = i + 1 ; j <= n ; j ++ )
        {
            sum = 0;
            for( int k = 0 ; k < m ; k ++ )
                sum += abs( s[i][k] - s[j][k] );
            res = min( res , sum );
        }
    cout << res << endl;

}

int main(){
    int t = read();
    while( t -- )
        solve();
    return 0;
}

D. X-Sum

\(n^3\)解法

這個是顯然的一種做法,就是直接枚舉出每一個點,然後計算出和就好

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

int lcm(  int x , int y ){
    return x * y / __gcd( x , y ) ;

}

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}
const int N = 500;

int n , m , sum , res;
int st[N][N];

void solve(){
    n = read() , m = read();
    for( int i = 1 ; i <= n ; i ++ )
        for( int j = 1 ; j <= m ; j ++ )
            st[i][j] = read();
    res = 0;
    for( int i = 1 ; i <= n ; i ++ )
        for( int j = 1 ; j <= m ; j ++ )
        {
            sum = st[i][j];
            for( int x = i-1 , y = j-1 ; x >= 1 && y >= 1 ; x -- , y -- )
                sum += st[x][y];
            for( int x = i-1 , y = j+1 ; x >= 1 && y <= m ; x -- , y ++ )
                sum += st[x][y];
            for( int x = i+1 , y = j-1 ; x <= n && y >= 1 ; x ++ , y -- )
                sum += st[x][y];
            for( int x = i+1 , y = j+1 ; x <= n && y <= m ; x ++ , y ++ )
                sum += st[x][y];
            res = max( res , sum );
        }
    cout << res <<'\n';
}

int main(){
    int t = read();
    while( t -- )
        solve();
    return 0;
}

\(n^2\)做法

可以首先計算出每一條斜線的和,然後再列舉一下中心點把兩條斜線加起來即可

那麼如何判斷點在哪條斜線上呢?

一條左斜的斜線距離\((1,1)\)的尤拉距離相同, 同理一條右斜的斜線距離\((n,n)\)的尤拉距離相同

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

int lcm(  int x , int y ){
    return x * y / __gcd( x , y ) ;

}

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}
const int N = 500;

int n , m , sum , res;
int st[N][N] , lc[2*N] , rc[2*N];

void solve(){
    n = read() , m = read();
    memset( lc , 0 , sizeof(lc) ) , memset( rc , 0 , sizeof(rc) );
    for( int i = 1 ; i <= n ; i ++ )
        for( int j = 1 ; j <= m ; j ++ )
            st[i][j] = read();
    int l , r ;
    for( int i = 1 ; i <= n ; i ++ )
        for( int j = 1 ; j <= m ; j ++ )
        {
            l = i - 1 + j - 1 , r = n - i + j - 1;
            lc[l] += st[i][j] , rc[r] += st[i][j];
        }

    res = 0;

    for( int i = 1 ; i <= n ; i ++ )
        for( int j = 1 ; j <= m ; j ++ )
        {
            l = i - 1 + j - 1 , r = n - i + j - 1;
            sum = lc[l] + rc[r] - st[i][j];
            res = max( res , sum );
        }
    cout << res << endl;
}

int main(){
    int t = read();
    while( t -- )
        solve();
    return 0;
}

E. Eating Queries

有 n 顆糖果,每個糖果有一個甜度\(a_i\),問需要甜度\(x\)至少要吃多少個糖果,每次詢問相互獨立

首先糖果數要少,就要優先吃甜度高的糖果。

把糖果從大到小排序,然後求一個字首和,對於每次的詢問在字首和二分查詢即可

#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}
const int N = 2e5+5;

int n , a[N] , m ;

void solve(){
    n = read() , m = read();
    for( int i = 1 ; i <= n ; i ++ )
        a[i] = read();
    sort( a + 1 , a+1+n , greater<int>() );
    for( int i = 1 ; i <= n ; i ++ )
        a[i] += a[i-1];
    for( int x , t ; m ; m -- )
    {
        x = read();
        if( x > a[n] )
            printf("-1\n");
        else
        {
            t = lower_bound( a+1 , a+1+n , x ) - a;
            printf("%lld\n" , t );
        }
    }
}

int32_t main(){
    int t = read();
    while( t -- )
        solve();
    return 0;
}

F. Longest Strike

給定一個序列,找出一個最長的區間,區間中的每個數都至少出現了 k 次

可以在 map 開一個桶來記錄,同時因為的 map 內部本身可以排序的,我們掃一邊就好了

注意的是,在掃的過程中我們判斷當前數是否是大於等於 k 以外還要判斷當前數是否和上一個數相鄰

#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;


int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}
const int N = 2e5+5;

int n , t , l , r ;
map< int , int > st;

void solve(){
    n = read() , t = read();
    st.clear();
    for( int i = 1 , x ; i <= n ; i ++ )
        x = read() , st[x] ++;
    int res = -1 , last = -1e9 , lastk = -1e9;
    for( auto [k,v] : st ){
        if(v >= t ){
            if( last == -1e9 || lastk+1 != k ) last = k;
            if( k - last > res )
                res = k - last , l = last , r = k;
        }
        else last = -1e9;
        lastk = k;
    }
    if( res == -1 ) printf("-1\n");
    else cout << l << ' ' << r << endl;
}

int32_t main(){
    int t = read();
    while( t -- )
        solve();
    return 0;
}

G. White-Black Balanced Subtrees

給一個樹,樹上的每一個點都已一個顏色黑或者白,問有多少個點滿足子樹中的黑白點數量相同

看似複雜實際上就是直接用 dfs 過程中統計下子樹中黑白點的數量就好了

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

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}

const int N = 4005;
int n , cnt , b[N] , w[N];
vector<int> e[N];
string s;

void dfs( int x ){
    if( s[x-1] == 'B' ) b[x] ++;
    else w[x] ++;
    for( auto v : e[x] ){
        dfs( v );
        b[x] += b[v] , w[x] += w[v];
    }
    if( b[x] == w[x] ) cnt ++ ;
}

void solve(){
    n = read() , cnt = 0;
    for( int i = 1 ; i <= n ; i ++ )
        e[i].clear() , b[i]  = w[i] = 0;

    for( int i = 2 , u ; i <= n ; i ++ )
        u = read() , e[u].push_back(i);
    cin >> s;
    dfs( 1 );
    cout << cnt << endl;
}

int32_t main(){
    int t = read();
    while( t -- )
        solve();
    return 0;
}

H. Maximum Crossings

有兩條線段,每個線段有 n 段 給定第一條線段與第二條線段連線的區間,問最多有多少個交點

這題有兩個版本,我直接寫的困難版本

其實這個題就是一個模板題,就是一個逆序對,只不過需要考慮一下邊界

#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch<'0'||ch>'9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = (x<<3)+(x<<1) + ch-'0' , ch = getchar();
    return x*f;
}

#define lowbit(x) ( x & -x )

const int N = 2e5+5;
int n , c[N] , cnt;

inline void update( int x ) // 更新 bit[x] += 1
{
    for( int i = x ; i <= n ; i += lowbit( i ) ) c[i] += 1;
}

inline int get( int x ) //求a[1...x]
{
    int ans = 0;
    for( int i = x ; i ; i -= lowbit( i ) ) ans += c[i];
    return ans;
}

void solve(){
    n = read() , cnt = 0;
    memset( c , 0 , sizeof (c) );
    for( int i = 1 , x ; i <= n ; i ++ )
    {
        x = read();
        cnt += i-1 - get(x-1);
        update(x);
    }
    cout << cnt << endl;
}

int32_t main(){
    int t = read();
    while( t -- )
        solve();
    return 0;
}