yuwj  

写都写了,记录一下

CF 1052 div2

码量最大的一场CF,目前为止自己写过的,就是没想那么透彻了

首次被人机验证单杀了,1h 写完的 B,2h才交上去,

本来这场上大分的,可恶

A

思路:

按数量排序从小到大枚举数量维护 max 就好了

void Solve(){
	cin >> n;
	vector<int> num(n+1);
	map<int,int> cnt;
	For(i,1,n) cin >> num[i], cnt[num[i]]++;
	vector<pii> todo;
	for(auto [x, cc ] : cnt) todo.emplace_back(cc,x);
	sort(all(todo));
	ll ans = 0; m = todo.size();
	for(int i=0;i<todo.size();++i) {
		auto [cc, x] = todo[i];
		ans = max(ans, cc*(m-i));
	}
	cout << ans << '\n';
}

B

思路:

就是分为几个必选集合和选选集合,选选 + 剩下的数量 >= 2 就有至少三种选法,

代码就是枚举值域,枚举下标,就是这个模拟这个过程,由于数据量较小,可以不用担心TLE

其实交的时候也没底


void Solve(){
	// chose n - chose >= 2,
	cin >> n >> m;
	vector<int> vis(m+1), ord(n+1);
	vector<vector<int>> S(n+1), pos(m+1);
	vector<set<int>> SSt(n+1);
	For(i,1,n){
		cin >> k;
		S[i].assign(k+1,0);
		For(j,1,k) cin >> S[i][j], pos[S[i][j]].pb(i), SSt[i].insert(S[i][j]);
	}

	set<int> chose, extra;
	bool ok = 1;
	For(i,1,m){
		if(pos[i].size() == 1) chose.insert(pos[i].front());
		else if(pos[i].size() == 0) ok = 0;
	}

	if(!ok) return puts("NO"), void();

	for(auto id : chose){
		auto v = S[id];
		for(auto x : v) vis[x] = 1;
	}

	// for(auto id : chose) cerr << id << ' ';
	// cerr << '\n';

	// For(i,1,m) cerr << vis[i] << " \n"[i == m];

	For(i,1,m) if(!vis[i]) extra.insert(i);

	set<int> st;
	int cnt = 0;
	if(extra.size()){
		For(i,1,n){
			bool tot = 1;
			for(auto x : extra) if(SSt[i].find(x) == SSt[i].end()) {tot = 0; break;}
			cnt += tot;
			if(cnt >= 2) break;
		}
	}
	//cerr << chose.size() << ' ' << cnt << "\n";
	puts(cnt + n - chose.size() >= 2 ? "YES" : "NO");
}

C

思路:

观察样例,猜测 1 的可行位置组成是左边都更小,右边都更大,

所以存在长度为 1 的 0 子串就肯定无法构造,这样就无法保证左右两边的排列了

反之,1 的情况,肯定是 ai = i

同时特判一下全 0 的情况

实现就是处理 0 串就好了,偶数 0 串,两两交换,奇数 0 串,前面 两两交换,最后 3 个数字变成 3 1 2 的结构就行,就是交换两次,或者说比偶数情况多换一次就能保证了

代码好丑

void solve(){
    cin >> n >> s, s = " " + s;
    
    bool ok = 1;
    For(i,1,n)if(s[i] == '0'){
        int j = i;
        while(j<=n && s[j] == '0') ++j;
        int len = j - i;
        if(len == 1) ok = 0;
        i = j-1;
    }
    vector<int> ans(n+1);
    iota(all(ans),0);
    if(count(all(s), '0') != n && !ok) return cout << "NO\n", void();
    if(count(s.begin()+1,s.end(),'0') == n){
        // 2 4 3 5 1
        vector<int> odd, even;
        int l = 1, r = n;
        For(i,1,n) {
            if(i%2 == 0) ans[l++] = i;
            else ans[r--] = i;
        }
    }else{
        For(i,1,n)if(s[i] == '0'){
            int j = i;
            while(j<=n && s[j] == '0') ++j;
            int len = j - i; --j;
            if(len & 1){
                for(int k=i;k<=j-3;k+=2) swap(ans[k], ans[k+1]);
                swap(ans[j], ans[j-1]); swap(ans[j-1],ans[j-2]);
            }else{
                for(int k=i;k<=j;k+=2) swap(ans[k],ans[k+1]); 
            }
            i = j;
            // cerr << i << '\n';
        }
    }

    cout << "YES\n";
    For(i,1,n) cout << ans[i] << " \n"[i == n];
}

D1 && D2(补)

参考题解:https://www.cnblogs.com/maburb/p/19104442

思路:

就是 01 Trie 上插入每个数字 [l,r],每个数字都去找或起来最大值,如果两个数字找到了对方就可以配对,同时在Trie中删除这两个数字,一直重复这个过程,直到所有数字填完为止

代码:

#include <bits/stdc++.h>
#define For(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
#define all(v) v.begin(),v.end()
#define int ll
using namespace std;
using ll = long long;
using pii = pair<int,int>;
ll qmi(ll a, ll k, int m){ll res=1;while(k){if(k&1)res=res*a%m;a=a*a%m;k>>=1;}return res;}
const int Maxn = 2e5 + 10, Mod = 998244353;
int n,m,k,x,y,t,c,l,r,q,num[Maxn];
vector<int> G[Maxn];
string s, Map[Maxn];

struct Trie{
    struct node {
        std::array<int, 2> son;
        node() : son{} {}
        int cnt = 0;
    };

    std::vector<node> t;
    Trie() {init();}
    void init() {t.assign(1, node());}

    int newnode() {
        t.reserve(500000);
        t.emplace_back();
        return t.size() - 1;
    }

    void insert(const int &val) {
        int p = 0;
        for (int i = 30; i >= 0; i--) {
            int ne = val >> i & 1;
            if (t[p].son[ne] == 0) {
                t[p].son[ne] = newnode();
            }
            p = t[p].son[ne];
            t[p].cnt++;
        }
    }

    int query(int x){
        int res = 0, p = 0;
		for(int i=30;i>=0;--i){
			int bit = x >> i & 1;
			if(bit == 0) {
				if(t[p].son[1] && t[t[p].son[1]].cnt){
					res |= (1ll << i);
					p = t[p].son[1];
				}else{
					p = t[p].son[0];
				}
			}else{
				if(t[p].son[0] && t[t[p].son[0]].cnt){
					p = t[p].son[0];
				}else{
					res |= (1ll << i);
					p = t[p].son[1];
				}
			}
		}
		return res;
    }

	void del(int x){
		int p = 0; // 虚拟节点
		for(int i=30;i>=0;--i){
			int bit = x >> i & 1;
			p = t[p].son[bit];
			t[p].cnt--; // 先到儿子再删
		}
	}

}trie;

void Solve(){
	cin >> l >> r;
	n = r - l + 1;
	trie.init();
	For(i,l,r) trie.insert(i);

	vector<int> ans(n+1,-1);

	while(1){
		bool flg = 0;
		vector<int> match(n+1,-1);
		For(i,l,r){
			if(ans[i-l] == -1){
				match[i-l] = trie.query(i);
				flg = 1;
			}
		}
		if(!flg) break;

		For(i,l,r){
			if(match[i-l] == -1) continue;
			if(i == match[match[i-l]-l]){ // match[match[j]] = i // i 和 j 相互配对,i 找 j,j 找 i,找回 i,就行了
				ans[i-l] = match[i-l];
				trie.del(i);
			}
		}
	}

	ll sum = 0;
	For(i,l,r) sum +=(ans[i-l] | i);
	cout << sum << '\n';
	For(i,l,r) cout << ans[i-l]<<" \n"[i==r];
}

signed main(){
	ios::sync_with_stdio(0);cin.tie(0);
	int t = 1;
	cin >> t;
	For(_,1,t) {Solve();}
	return 0;
}
/**
 *  心中无女人
 *  比赛自然神
 *  模板第一页
 *  忘掉心上人
**/
posted on 2025-09-22 10:14  xiaowang524  阅读(23)  评论(0)    收藏  举报