Codeforces Round 855 (Div. 3) A-G完全题解

比赛链接

A

没啥好说的。(其实比赛时写丑了。把字母全部统一成小写更好,因为大小写不影响)

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

template <class T>
inline void read(T& a){
    T x = 0, s = 1;
    char c = getchar(); 
    while(!isdigit(c)){ if(c == '-')  s = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
    a = x * s;
    return ; 
}

bool judge(char s, int x){
    if(s == x || s == x - 'A' + 'a') return 1; 
    else return 0; 
}

char s[10001]; 

int main(){
    //freopen("hh.txt", "r", stdin); 
    int T; read(T); 
    while(T--){
        int n; read(n); 
        cin >> s; 
        int len = strlen(s); 
        bool flag = 1; 
        int id = 0; 
        bool vis[4]; 
        memset(vis, 0, sizeof(vis)); 
        while(s[id] == 'm' || s[id] == 'M' && id < len) id++, vis[0] = 1; 
        if(s[id] != 'e' && s[id] != 'E') flag = 0; 
        while(s[id] == 'e' || s[id] == 'E' && id < len) id++, vis[1] = 1; 
        if(s[id] != 'o' && s[id] != 'O') flag = 0; 
        while(s[id] == 'o' || s[id] == 'O') id++, vis[2] = 1; 
        if(s[id] != 'w' && s[id] != 'W') flag = 0; 
        while(s[id] == 'w' || s[id] == 'W') id++, vis[3] = 1; 
        if(id <= len - 1) flag = 0; 
        for(int i = 0; i < 4; i++) flag &= vis[i]; 
        if(!flag) puts("NO"); 
        else puts("YES"); 
    }
    return 0; 
}   

B

用两个数组记录大小写数量即可。

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

template <class T>
inline void read(T& a){
    T x = 0, s = 1;
    char c = getchar(); 
    while(!isdigit(c)){ if(c == '-')  s = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
    a = x * s;
    return ; 
}


map <int, int> g; 

int main(){
    //freopen("hh.txt", "r", stdin); 
    int T; read(T);
    while(T--){
        g.clear(); 
        int n, k;
        read(n); read(k);
        string s; cin >> s; 
        for(int i = 0; i < s.length(); i++){
            g[s[i]]++; 
        }
        int ans = 0; 
        for(int i = 'a'; i <= 'z'; i++){
            int x = i - 'a' + 'A'; 
            int minn = min(g[x], g[i]); 
            ans += minn; 
            g[x] -= minn, g[i] -= minn; 
            int maxn = max(g[x], g[i]); 
            int num = maxn / 2; 
            if(k >= num){
                ans += num; 
                k -= num; 
            }
            else{
                ans += k; 
                k = 0; 
            }            
        }
        cout << ans << endl; 
    }
    return 0; 
}   

C (\(easy & hard\)

显然,每次遇到 \(0\), 我们都可以优先去取前面最大的值。所以用堆维护一下即可。

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

template <class T>
inline void read(T& a){
    T x = 0, s = 1;
    char c = getchar(); 
    while(!isdigit(c)){ if(c == '-')  s = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
    a = x * s;
    return ; 
}

priority_queue <int> q; 

int main(){
    //freopen("hh.txt", "r", stdin); 
    int T; read(T);
    while(T--){
        while(!q.empty()) q.pop(); 
        int n; 
        read(n);
        ll ans = 0;  
        for(int i = 1; i <= n; i++){
            int x; read(x); 
            if(x != 0) q.push(x); 
            else{
                if(q.empty()) continue; 
                else{
                    ans += q.top(); 
                    // printf("x: %d top: %d\n", x, q.top()); 
                    q.pop(); 
                }
            }
        }
        cout << ans << endl; 
    }
    return 0; 
}   

D.

直接分类讨论。一长串完全相同的肯定只能算一个。两个不同的字母交界处也算一个。但是形如 \(aba\) 这种的又要减去一个,算重复了。

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

template <class T>
inline void read(T& a){
    T x = 0, s = 1;
    char c = getchar(); 
    while(!isdigit(c)){ if(c == '-')  s = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
    a = x * s;
    return ; 
}


int main(){
    //freopen("hh.txt", "r", stdin); 
    int T; read(T);
    while(T--){
        int n; read(n);
        string s; cin >> s; 
        int ans = 0; 
        for(int i = 1; i < s.length(); i++){
            if(s[i] != s[i-1]) ans++; 
            if(s[i] == s[i-1] && s[i] != s[i+1]) ans++; 
            if(s[i] == s[i-1] && s[i] == s[i+1]) continue;  
        }
        for(int i = 0; i < s.length() - 2; i++){
            if(s[i] != s[i+1] && s[i] == s[i + 2]) ans--; 
        }
        cout << ans << endl; 
    }
    return 0; 
}   

E (easy & hard)

手玩一下可以知道,对于那些可以移动的字母,他们是可以任意移动的。所以不妨把原串分为三部分: \([可动] [不可动] [可动]\)。 其中左右两侧的可动区域字母可以在两个总区域内随意移动。不可动区域则直接按原串比较即可。

#include<bits/stdc++.h>
using namespace std ;
#define maxn 400100
#define int long long
int read(){
	int ans = 0 , f = 1 ; char ch = getchar() ;
	while ( !isdigit(ch) ){ if( ch == '-' ) f = -1 ; ch = getchar() ; }
	while ( isdigit(ch) ) ans = (ans * 10) + (ch ^ '0') , ch = getchar() ;
	return ans * f ;
}
int t ; 
char in1[maxn] , in2[maxn] ; 
int n   , k  ; 
int cnt1[30] , cnt2[30] ; 
signed main(){
	t = read() ; 
	while(t--){
		n = read() , k = read() ; 
		memset(cnt1 , 0 , sizeof(cnt1)) ; 
		memset(cnt2 , 0 , sizeof(cnt2)) ; 
		scanf("%s" , in1 + 1) ; 
		scanf("%s" , in2 + 1) ; 
		if(k * 2 <= n ){
			for(int i = 1 ;  i <= n ; i++)
				cnt1[in1[i] -'a'+ 1]++ ; 
			for(int i = 1 ; i <= n ; i++)
				cnt2[in2[i] -'a'+ 1]++ ; 
			bool flag = 0 ; 
			for(int i = 1 ; i <= 26 ; i++)
				if(cnt1[i] != cnt2[i]) flag = 1 ; 
			if(flag == 1){
				printf("no\n") ; 
			}
			else printf("yes\n") ; 
		}
		else if(k >= n){
			bool flag = 0 ; 
			for(int i = 1 ; i <= n ; i++)	
				if(in1[i] != in2[i] )
					flag = 1 ; 
			if(flag == 1){
				printf("no\n") ; 
			}
			else printf("yes\n") ; 
		}
		else if(k * 2 > n){
			for(int i = 1 ; i <= n - k ; i++)
				cnt1[in1[i] -'a'+ 1]++ ,cnt2[in2[i] -'a'+ 1]++ ;
			for(int i = k + 1 ; i <= n ; i++)
				cnt1[in1[i] -'a'+ 1]++ ,cnt2[in2[i] -'a'+ 1]++ ;
			bool flag = 0 ; 
			for(int i = 1 ; i <= 26 ; i++)
				if(cnt1[i] != cnt2[i]) flag = 1 ; 
			for(int i = n - k + 1 ; i <= k ; i++)
				if(in1[i] != in2[i])
					flag = 1 ; 
			if(flag == 1){
				printf("no\n") ; 
			}
			else printf("yes\n") ; 
		}
	}
	return 0 ;
 }


F

发现结果只跟奇偶性以及是否存在有关,与具体数量无关。所以考虑先把所有串化成 \(01\) 串。(\(0\) 表示没有或偶数个,\(1\) 表示奇数个)。然后,考虑枚举某一个字母被消去,则我们可以提前得到最终目标形态:一个有 \(25\)\(1\)\(1\)\(0\)\(01\) 串。

这样,我们枚举每个串,确认其不含有某个字母时,将目标状态与其异或一下,便能得到对应符合要求的串。

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

template <class T>
inline void read(T& a){
    T x = 0, s = 1;
    char c = getchar(); 
    while(!isdigit(c)){ if(c == '-')  s = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
    a = x * s;
    return ; 
}

int n; 
char s[5000010]; 
unordered_map <int, int> g[27];  // 某个状态在缺失某个字母下对应的个数
int target[27];  // 某个字母不出现的情况下,我们的目标状态

int main(){
//	freopen("hh.txt", "r", stdin);  
    for(int i = 0; i < 26; i++){
        target[i] = ((1 << 26) - 1) ^ (1 << i);      
    }
    ll ans = 0; 
    read(n);        
    for(int i = 1; i <= n; i++){
        scanf("%s", s); 
        int num[27] = {0};
        int len = strlen(s);  
        for(int j = 0; j < len; j++){
            num[s[j] - 'a']++; 
        }
        int now = 0; 
        for(int j = 'a'; j <= 'z'; j++){
            if(num[j - 'a'] % 2 == 1){
                now |= (1 << (j - 'a')); 
            } 
        }
        for(int j = 'a'; j <= 'z'; j++){  // 二者都缺失这个字母的情况下
            if(num[j - 'a'] == 0){
                ans += g[j - 'a'][target[j - 'a'] ^ now]; 
            }
        }
        for(int j = 'a'; j <= 'z'; j++){
            if(num[j - 'a'] == 0)
                g[j - 'a'][now]++; 
        }
    }
    cout << ans << endl;
    return 0; 
}

G

数哈希模板题。代码用了比较方便的 \(unsigned\) 自然溢出。
值得一提的是 \(check\) 函数,分类讨论奇偶。注意到可能会有多个奇数点,因此采用可以嵌套的递归方式最为方便。

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

template <class T>
inline void read(T& a){
    T x = 0, s = 1;
    char c = getchar(); 
    while(!isdigit(c)){ if(c == '-')  s = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); }
    a = x * s;
    return ; 
}

vector <int> G[N]; 

int n; 
int siz[N]; 
vector <unsigned int> hah;  // 哈希值

const unsigned int seed =  (chrono::steady_clock::now().time_since_epoch().count());
unsigned int shift(unsigned int x){  // 自然溢出
    x ^= seed; 
    x ^= x << 13;
    x ^= x >> 7;
    x ^= x << 17;
    x ^= seed;
    return x; 
}

int fa[N]; 
void dfs(int u, int father){
    fa[u] = father; 
    siz[u] = 1; 
    hah[u] = 1; 
    for(auto v : G[u]){ 
        if(v != father){
            dfs(v, u); 
            hah[u] += shift(hah[v]); 
        }
    }
    return ; 
}   

bool check(int u){
    map <int, int> g; 
    for(auto v : G[u]){
        if(v == fa[u]) continue; 
        g[hah[v]]++; 
    }
    bool flag = 1; 
    int Size = 0; 
    if(u == 1) Size = G[u].size(); 
    else Size = G[u].size() - 1;  // 剪掉父亲, 获取子节点数量
    if(Size % 2 == 0){
        for(auto v : G[u]){
            if(v == fa[u]) continue; 
            if(g[hah[v]] % 2 == 1) flag = 0; // 偶数情况下存在落单值
        }
    }
    else{
        int num = 0; 
        int id = 0; 
        map <int, int> vis; 
        for(auto v : G[u]){
            if(v == fa[u]) continue; 
            if(g[hah[v]] % 2 == 1 && !vis[hah[v]]){ // 这里需要统计有多少个奇数,所以用 vis 去重
                num++; 
                id = v; 
                vis[hah[v]] = 1; 
            }
        }
        if(num > 1) flag = 0; // 大于 1 个单配的
        else{
            flag &= check(id); // 检查下一层
        } 
    }
    return flag; 
}

void clean(){
    for(int i = 1; i <= n; i++)
        G[i].clear();
    hah.clear(); 
    return ; 
}

int main(){
    //freopen("hh.txt", "r", stdin); 
    int T; read(T);
    while(T--){
        read(n);
        for(int i = 1; i < n; i++){
            int u, v; 
            read(u), read(v); 
            G[u].push_back(v);
            G[v].push_back(u); 
        }
        for(int i = 1; i <= n + 100; i++)
            hah.push_back(0); 
        dfs(1, 0);
        bool flag = check(1); 
        if(flag) puts("Yes");
        else puts("No"); 
        clean(); 
    }
    return 0; 
}   
posted @ 2023-03-11 01:44  雪之下,树之旁  阅读(58)  评论(0编辑  收藏  举报