写都写了,记录一下
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;
}
/**
* 心中无女人
* 比赛自然神
* 模板第一页
* 忘掉心上人
**/

浙公网安备 33010602011771号