VP Codeforces Round 906 (Div. 2)


A. Doremy's Paint 3

题意:给你你个数组,你要重排它使得每两个相邻数的和都相同。

a1+a2=a2+a3,那么a1=a3a2+a3=a3+a4,那么a2=a4,然后发现奇数位置都相等,偶数位置都相等。那么数组只有一类数明显可以,如果有两类数,判断是不是有各占n2个即可,注意n为奇数的情况有一类数会多占一个。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    std::set<int> s;
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    	s.insert(a[i]);
    }

    int cnt = 0;
    for (int i = 0; i < n; ++ i) {
    	cnt += a[i] == a[0];
    }

    if ((s.size() == 2 && (cnt == n / 2 || cnt == (n + 1) / 2)) || s.size() == 1) {
    	std::cout << "YES\n";
    } else {
    	std::cout << "NO\n";
    }
}

B. Qingshan Loves Strings

题意:给你两个01s,t,你每次可以把t插到s的任意位置,求能不能使得s相邻的数都不相同。

如果s本来不满足条件并且t也不满足条件,则无解。否则考虑插入t,如果si==si+1,那么则需要插入t,判断t插入后是不是满足要求。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::string s, t;
    std::cin >> s >> t;

    bool flag = true;
    for (int i = 1; i < n; ++ i) {
    	flag &= s[i] != s[i - 1];
    }

    if (flag) {
    	std::cout << "YES\n";
    	return;
    }

    flag = true;
    for (int i = 1; i < m; ++ i) {
    	flag &= t[i] != t[i - 1];
    }

    if (flag) {
    	for (int i = 1; i < n; ++ i) {
    		if (s[i] == s[i - 1]) {
    			if (s[i - 1] == t[0] || s[i] == t.back()) {
    				std::cout << "NO\n";
    				return;
    			}
    		}
    	}

    	std::cout << "YES\n";
    	return;
    }

    std::cout << "NO\n";
}

C. Qingshan Loves Strings 2

题意:给你一个01s,你可以在任意位置插入01,设最后s的长度为k,求能不能使得最后所有的i[1,k],si!=sni+1

首先每次插入都会使得01的数量加一,这不影响它们的差,那么一开始01的个数就要相等。
假设[1,i1],[ni+2,n]都已经满足要求,那么如果si==sni+1,当si==0,则在sni+1的后面插入01 ,否则在i的前面插入01,发现这样操作最后一定满足要求。暴力模拟即可。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::string s;
    std::cin >> s;
   	int cnt[2]{};
   	for (auto & c : s) {
   		++ cnt[c - '0'];
   	}

   	if (cnt[0] != cnt[1]) {
   		std::cout << -1 << "\n";
   		return;
   	}

   	std::vector<int> ans;

   	auto insert = [&](int p) -> void {
   		ans.push_back(p);
   		s = s.substr(0, p + 1) + "01" + s.substr(p + 1);
   	};

   	for (int l = 0, r = n - 1; l < r; ++ l, -- r) {
   		if (s[l] == s[r]) {
   			if (s[l] == '0') {
   				insert(r);
   				r += 2;
   			} else {
   				insert(l - 1);
   				r += 2;
   			}
   		}
   	}

   	std::cout << ans.size() << "\n";
   	for (auto & p : ans) {
   		std::cout << p + 1 << " \n"[p == ans.back()];
   	}
}

D. Doremy's Connecting Plan

题意:一开始有n个集合,第i个集合的值为ai。你每次选择两个位置i,j,设i所在集合的值为Sij所在集合的值为Sj。那么如果Si+Sji×j×c则可以合并这两个集合,新集合的值为Sa+Sb。求能不能合并成一个集合。

我们一定是选两个集合最小的两个位置操作,因为这样i×j最小,那么发现,我们一开始一定可以选1和某个位置操作,利用反证法,假设一开始选择(i,j)进行操作i1,j1,并且(1,i)(1,j)都无法操作。那么有ai+aji×j×cai+a1<1×i×c, aj+a1<1×j×c, 那么得到ai+aj+2ai<(i+j)×c,由于i1,j1,那么i×ji+j,于是产生矛盾。
那么我们现在改一下式子:Si+Sji×j×c==>Sii×j×cSj,根据贪心策略,我们一定是每次选1和其它位置操作,那么式子就是S1j×cSj,于是按j×cSj排序,从小到大合并。

点击查看代码
void solve() {
    int n;
    i64 c;
    std::cin >> n >> c;
    std::vector<std::array<i64, 3>> a(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	i64 x;
    	std::cin >> x;
    	a[i] = {i * c - x, x, i};
    }

    std::sort(a.begin() + 2, a.end());
    i64 sum = a[1][1];
    for (int i = 2; i <= n; ++ i) {
    	if (sum < a[i][0]) {
    		std::cout << "NO\n";
    		return;
    	}

    	sum += a[i][1];
    }

    std::cout << "YES\n";
}

E1. Doremy's Drying Plan (Easy Version)

题意:有n个线段,你要删除其中两个,使得没有被线段覆盖过的点最多。

分成两种情况:

  1. 两个线段不相交
  2. 两个线段相交

我们先利用差分算出每个点被多少线段覆盖。
对于第一种情况,我们记录线段覆盖的区间中只被1个线段覆盖的点的最大值和次大值。如果最终答案为不相交的两个线段,那么显然求出来的就是答案,否则最终答案为两个相交的线段,则求出来的值一定小于第二种情况的值。
对于第二种情况,我们用优先队列存每个线段的右端点和左端点,先把线段存在数组里按左端点排序,然后从小到大枚举,对于每个左端点为i的线段都加进来,然后对于每个前面加进来的线段的右端点小于i的线段都删去,那么就得到了每个点被覆盖的线段。如果这个点恰好被两个线段覆盖,那么就取出来更新答案。

点击查看代码
void solve() {
    int n, m, k;
    std::cin >> n >> m >> k;
    using PII = std::pair<int, int>;
    std::vector<PII> segs;
    std::vector<int> d(n + 2);
    for (int i = 0; i < m; ++ i) {
    	int l, r;
    	std::cin >> l >> r;
        segs.push_back({l, r});
    	d[l] += 1;
    	d[r + 1] -= 1;
    }

    std::vector<int> one(n + 1), two(n + 1);
    int ans = 0;
    for (int i = 1; i <= n; ++ i) {
        d[i] += d[i - 1];
        one[i] = one[i - 1];
        two[i] = two[i - 1];
        if (d[i] == 0) {
            ++ ans; 
        } else if (d[i] == 1) {
            ++ one[i];
        } else if (d[i] == 2) {
            ++ two[i];
        }
    }

    int max1 = 0, max2 = 0;
    for (auto & [l, r] : segs) {
        int cnt = one[r] - one[l - 1];
        if (cnt >= max1) {
            max2 = max1;
            max1 = cnt;
        } else if (cnt > max2) {
            max2 = cnt;
        }
    }

    int ans1 = max1 + max2;
    std::sort(segs.begin(), segs.end());
    std::priority_queue<PII, std::vector<PII>, std::greater<>> heap;
    for (int i = 1, t = 0; i <= n; ++ i) {
        while (heap.size() && heap.top().first < i) {
            heap.pop();
        }

        while (t < m && segs[t].first == i) {
            heap.push({segs[t].second, segs[t].first});
            ++ t;
        }

        if (heap.size() == 2) {
            auto [a1, a2] = heap.top(); heap.pop();
            auto [a3, a4] = heap.top();
            std::vector<int> a{a1, a2, a3, a4};
            std::sort(a.begin(), a.end());
            int cnt = one[a[3]] - one[a[0] - 1] + two[a[2]] - two[a[1] - 1];
            ans1 = std::max(ans1, cnt);
            heap.push({a1, a2});
        }
    }

    std::cout << ans + ans1 << "\n";
}
posted @   maburb  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示