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;
}
posted @ 2022-05-24 15:37  PHarr  阅读(88)  评论(0编辑  收藏  举报