Codeforces Round #843 (Div. 2)(较难场)A1-D题解

比赛链接

A. Gardener and the Capybaras (easy or hard version)

分类讨论即可。
如果第一个字符串以 \(a\) 开头,我们先考虑找一个在中间的 \(b\), 如果存在,则从这个 \(b\) 一直到倒数第二个字符规定为第二个字符串,确保其为最大的。如果不存在这个 \(b\), 那么就是除了最后一个字符全都一定是 \(a\), 那么直接把第二个字符串规定为第二个字符 \(a\) 即可,确保其为最小的。

第一个字符串以 \(b\) 开头时同理。
这样就一次性解决了 \(easy\)\(hard version\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
#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; cin >> T;
    while(T--){
        string s; 
        cin >> s; 
        string a = "", b = "", c = ""; 
        if(s[0] == 'b'){
            int pos = s.length(); 
            for(int i = 0; i < s.length(); i++){
                if(s[i] == 'a'){
                    pos = i;
                    break; 
                }
            }
            if(pos < s.length() - 1){
                cout << s.substr(0, pos) << " ";
                cout << s[pos] << " "; 
                cout << s.substr(pos + 1, s.length() - pos - 1); 
                cout << endl; 
            }
            else cout << s[0] << " " << s[1] << " " << s.substr(2, s.length() - 2) << endl; 
        }
        else if(s[0] == 'a'){
            int pos = s.length(); 
            for(int i = 0; i < s.length(); i++){
                if(s[i] == 'b'){
                    pos = i;
                    break; 
                }
            }
            if(pos < s.length() - 1){
                cout << s.substr(0, pos) << " ";
                cout << s.substr(pos, s.length() - 1 - pos) << " "; 
                cout << s[s.length() - 1]; 
                cout << endl; 
            }
            else cout << s[0] << " " << s[1] << " " << s.substr(2, s.length() - 2) << endl; 
        }
    }
  	return 0;
}

B. Gardener and the Array

首先题目没有规定子串的长度。那么我们直接把所有的数字先全部 或 在一起。如果能找到某一个数字,将其删去后不会影响最终与在一起的结果,那么就是 \(Yes\)。否则就是 \(No\)

补充:获取整体的结果一定是不亏的。因为这是数字越多,删数字的要求也约"宽松"。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
#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[200010]; 

int main(){
	// freopen("hh.txt", "r", stdin); 
    int T; cin >> T;
    while(T--){
        int n; cin >> n; 
        map <int, int> num; 
        bool ans = 0; 
        
        for(int i = 1; i <= n; i++){
            G[i].clear(); 
            int k; cin >> k; 
            for(int j = 1; j <= k; j++){
                int p; cin >> p;
                num[p]++; 
                G[i].push_back(p); 
            }
        }

        for(int i = 1; i <= n; i++){
            bool flag = 1; 
            for(auto it : G[i]){
                if(num[it] <= 1) flag = 0; 
            }
            ans |= flag; 
        }
        if(ans) puts("YES"); 
        else puts("NO"); 
    }
  	return 0;
}

C. Interesting Sequence

首先注意到这是一个 与 操作,那么当我们从高到低遇到某一位 \(n\)\(1\)\(x\)\(0\) 时,这一位我们的 \(ans\) 一定只能填 \(0\)。但是我们要保证大小关系,所以将这一位前移保证答案比原数字大。这一位后面的全部抹零即可。(之后的数字无论如何增加,最终答案这一位永远都是 \(0\), 所以不用继续考虑别的情况。)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define N 100
#define ll long long
#define int 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 ;
}

ll n; 
ll x;

signed main(){
	// freopen("hh.txt", "r", stdin); 
    int T; read(T);
    while(T--){
        read(n), read(x); 
        bitset <N> a(n); 
        bitset <N> b(x); 
        if(a == b){
            cout << a.to_ullong() << endl;
            continue; 
        }
        if(x > n){
            puts("-1");
            continue; 
        }
        bool flag = 0; 
        ll sum = 0; 
        for(int i = 63; i >= 1; i--){
            if(((1ll << (i - 1)) & n) != 0){
                if(((1ll << (i - 1)) & x) == 0){
                    if(((sum + (1ll << i)) & x )== x){
                        cout << sum + (1ll << (i)) << endl; 
                        flag = 1; 
                    }
                    break; 
                }
                sum += (1ll << (i - 1));
            }


        }
        if(!flag) puts("-1"); 
    }
  	return 0;
}

D. Friendly Spiders

这题可以采用分解质因数的方法来解。可以看到,所有蜘蛛间的关系形成了一张图,如果我们能建出一张图,那么求一次最短路便能解决该问题。
下面考虑如何建图。如果对原数字进行暴力建图,首先边数会非常大,其次就是两两枚举求 \(GCD\) 的过程也是显然过不去的。

那么,就引出了分解质因数。不难发现,所有数字的质因数是有限的,而且 \(a_i\) 的范围也较小。例如,我们如果将 \(20\) 分解为 \(2\)\(5\), 只需要将 \(20\)\(2\)\(5\) 连边,再将 \(4\)\(2\) 连边,便完成了我们的建图操作。这样子做可以极大的减少我们的建边所需时间以及图的边数。同时也记得将数字与自己连边(质数)。边权全部设为 \(1\), 最终答案除以 \(2\) 即可。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define N 2000010
#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 ;
}

struct node{
    int u, v, w, next; 
} t[N << 1]; 
int head[N << 1]; 

int bian = 0;
inline void addedge(int u, int v, int w){
    t[++bian] = (node){u, v, w, head[u]}, head[u] = bian;
    return ; 
}

int n; 
int a[N]; 

set <int> s; 
map <int, int> g; 
set <int> G[N >> 1]; 
int S, T; 

struct point{
    ll d; 
    int id; 

    bool operator < (const point &a) const{
        return d > a.d; 
    }
} ; 

auto cmp = [](point a, point b){return a.d > b.d; }; 
ll dis[N]; 
bool vis[N]; 
int pre[N]; 

void dij(int S, int T){
    priority_queue <point> q; 
    memset(dis, 0x3f3f3f3f, sizeof(dis)); 
    dis[S] = 0; 
    q.push((point){0, S}); 
    while(!q.empty()){
        int u = q.top().id;  
        q.pop();  
        if(!vis[u]){
            vis[u] = 1; 
            for(int i = head[u]; i; i = t[i].next){
                int v = t[i].v;
                if(dis[v] > dis[u] + t[i].w){
                    dis[v] = dis[u] + t[i].w;
                    pre[v] = u; 
                    if(!vis[v]) q.push((point){dis[v], v}); 
                }
            }
        }
    } 
    return ; 
}

int ans[N]; 

signed main(){
    read(n); 
    for(int i = 1; i <= n; i++)
        read(a[i]); 
    int id = n;
    for(int i = 1; i <= n; i++)
        g[a[i]] = ++id; 

    for(int i = 1; i <= n; i++){
        vector <int> h; 
        for(int j = 2; j * j <= a[i]; j++){
            if(a[i] % j == 0) h.push_back(j), h.push_back(a[i] / j);
        }
        h.push_back(a[i]); 
        sort(h.begin(), h.end()); 
        int tmp = a[i]; 
        vector<int>::iterator it = h.begin(); 
        while(tmp != 1){
            if(tmp % *it == 0){
                tmp /= *it; 
                s.insert(*it); 
                G[i].insert(*it); 
            }
            else it++; 
        }
    }
    
    for(auto it : s){
        g[it] = ++id; 
    }
    
    for(int i = 1; i <= n; i++){
        for(auto it : G[i]){
            addedge(i, g[it], 1); 
            addedge(g[it], i, 1); 
        }
    }
    read(S), read(T);
    dij(S, T); 
    if(!vis[T]){
        puts("-1"); 
    }
    else{
        int num = 0; 
        cout << dis[T] / 2 + 1 << endl; 
        int now = T; 
        while(pre[now]){
            if(now <= n) ans[++num] = now; 
            now = pre[now]; 
        }
        printf("%d ", S); 
        for(int i = num; i; i--)
            printf("%d ", ans[i]); 
    }
    return 0; 
}

posted @ 2023-01-11 16:30  雪之下,树之旁  阅读(52)  评论(0编辑  收藏  举报