2024 信友队 noip 冲刺 10.4

T1

给定 n n n 个数 { a n } \{a_n\} {an},每次操作可以选择一个 i ∈ [ 1 , n ] i\in [1,n] i[1,n] 使得 a i ← a i − 1 a_i\gets a_i-1 aiai1。求最少操作次数使得 a a a 中除了 0 0 0 以外其他值至多出现 1 1 1 次。

n ≤ 2 × 1 0 5 n\le 2\times 10^5 n2×105 a i ∈ [ 0 , 1 0 6 ] a_i\in [0,10^6] ai[0,106]

直接在值域上考虑,令 t i t_i ti 表示值为 i i i 的元素个数,从大往小考虑,若 t i > 1 t_i>1 ti>1 那么需要执行 t i − 1 t_i-1 ti1 次操作令 t i ← 1 t_i\gets 1 ti1,与此同时会令 t i − 1 ← t i − 1 + t i − 1 t_{i-1}\gets t_{i-1}+t_i-1 ti1ti1+ti1;一直这么推下去推到 0 0 0 为止即可。如果值域大一些直接考虑有值的 n n n 个位置即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define open(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
const int maxn = 1e6 + 5;
ll t[maxn]; int n, a[maxn];
int main() {
	open(seq); 
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++)
		scanf("%d", &a[i]), t[a[i]] ++;
	ll ans = 0;
	for (int i = 1e6; i > 0; i --)
		if (t[i] > 1)
			ans += t[i] - 1, t[i - 1] += t[i] - 1;
	printf("%lld\n", ans);
	return 0;
}

T2

给定 n n n,构造一个仅包含 X , Y , D \texttt{X},\texttt{Y},\texttt{D} X,Y,D 三种字符的字符串使得 XYD \texttt{XYD} XYD 这个子序列恰好出现 n n n 次。要求串长 ≤ 6000 \le 6000 6000

n ≤ 1 0 9 n\le 10^9 n109

赛时糖丸了,推了一个关于平方的做法,差点就被我发现了。一个简单的做法是考虑在 X \texttt{X} X 后面放 YD \texttt{YD} YD 的贡献,发现若放了 n n n 个则产生了 n ( n + 1 ) 2 \cfrac{n(n+1)}{2} 2n(n+1) XYD \texttt{XYD} XYD 子序列(可能往上往下有出入,大概长这样),于是我们考虑把 n n n 拆成这么几段,先放一个由若干段 YD \texttt{YD} YD 循环组成的串,然后在对应位置插入若干个 X \texttt{X} X 即可。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2005;
#define ll long long
#define open(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
ll a[maxn];
int main() {
	open(xyd);
	int n, m; scanf("%d", &n);
	for (m = 1; m <= 2000; m ++)
		if (a[m - 1] + m > n) break; 
		else a[m] = a[m - 1] + m;
	for (m --; m > 0; m --, putchar('Y'), putchar('D'))
		for (; a[m] <= n; n -= a[m]) putchar('X');
	return 0;
}

T3

给定两个长度为 n n n 的序列 x , y x,y x,y,再给定 m m m 个长度为 n n n 的序列,对于第 i i i 个序列 a i a_i ai 选择以下操作之一进行:

  • 对于所有 j ∈ [ 1 , n ] j\in[1,n] j[1,n],令 x j ← max ⁡ ( x j , a i , j ) x_j\gets \max(x_j,a_{i,j}) xjmax(xj,ai,j)
  • 对于所有 j ∈ [ 1 , n ] j\in[1,n] j[1,n],令 y j ← max ⁡ ( y j , a i , j ) y_j\gets \max(y_j,a_{i,j}) yjmax(yj,ai,j)​。

要求按顺序操作,求操作后最大的 ∑ i = 1 n x i + y i \sum^n_{i=1}x_i+y_i i=1nxi+yi

n ≤ 10 n\le 10 n10 m ≤ 1 0 5 m\le 10^5 m105

先拼了一档 m ≤ 20 m\le 20 m20 的暴搜做法,然后又拼了一个乱搞做法:每次比较 x , y x,y x,y 产生的增量,哪个多操作哪个,最终骗到 72 p t s 72\mathrm{pts} 72pts。然后一种可行解是随机化,正确率还挺高。

T4

显然最小的取法就是从每个集合中取一个最小值求和,我们设这个最优值为 a n s ans ans。考虑其可能的后几个略小一些的状态。我们将每个集合按照次小值减最小值的差从小到大排序,每个集合内部按从小到大排序。假设当前状态 { i , j , w } \{i,j,w\} {i,j,w} 表示枚举到第 i i i 个集合中的第 j j j 个数,考虑将 a n s ans ans 中第 i i i 个集合取的数更换为 j j j更换后的答案为 w w w。令 c ( i , j ) c(i,j) c(i,j) 表示集合 i i i 中第 j j j 大的值,最初始的状态即为 { 1 , 2 , a n s − c ( 1 , 1 ) + c ( 1 , 2 ) } \{1,2,ans-c(1,1)+c(1,2)\} {1,2,ansc(1,1)+c(1,2)}。对于每个状态会有三个可能的分支:

  • 如果 j < s i z i j<siz_i j<sizi,则一种可能的选择即为放弃更换为 j j j,考虑更换为 j + 1 j+1 j+1。新的状态为 { i , j + 1 , w − c ( i , j ) + c ( i + j ) } \{i,j+1,w-c(i,j)+c(i+j)\} {i,j+1,wc(i,j)+c(i+j)}
  • 如果 i i i 不是最后一个集合:
    • 一种可能的选择即为决定更换为 j j j,开始考虑 i + 1 i+1 i+1 集合的选择。新的状态为 { i + 1 , 2 , w − c ( i + 1 , 1 ) + c ( i + 1 , 2 ) } \{i+1,2,w-c(i+1,1)+c(i+1,2)\} {i+1,2,wc(i+1,1)+c(i+1,2)}
    • 另外,如果 j = 2 j=2 j=2,则一种可能的选择即为放弃更换 i i i 中的元素,直接考虑 i + 1 i+1 i+1 集合的选择。新的状态为 { i + 1 , 2 , w − c ( i , 2 ) + c ( i , 1 ) − c ( i + 1 , 1 ) + c ( i + 1 , 2 ) } \{i + 1,2,w - c(i,2) + c(i,1) - c(i+1,1) + c(i+1,2)\} {i+1,2,wc(i,2)+c(i,1)c(i+1,1)+c(i+1,2)}

开一个优先队列记录这些状态,从中取 k k k​ 轮即为答案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值