icpc沈阳2026邀请赛vp补题记录
牢完了兄弟
昨天晚上头疼一晚上,脑子感觉怪怪的。疑似是吹空调导致的。。。早上醒来好多了,把电路翘了,把记录补一下。
上来先把 \(L\) 的题面读错,浪费了5分钟,然后过了签到后一眼看出 \(K\) 是断环成链+前缀和+区间最小值,懒得想了,打了一个线段树模板交一发,结果发现WA了,一看才发现前缀和的左端没有减一,改为过了 \(K\), 再去看 \(E\), 手玩了一下发现就是利用 \(0\) 来实现斜着走长度不变,写完交了一发,发现RE了,才发现数组开小了,改了一下就过了。再到 \(E\), 口胡了一个贪心做法,交上去不出意外WA了,想了半天,以为是贪心排序,结果推了半天的式子证明了相同情况下越小的放在前面越好(我去不早说),感觉 \(E\) 没啥说法就去看 \(I\) 了,感觉复杂度很玄学(看着很像24昆明 \(BFS\) 暴力过),写了一发,拿大数测了一下,发现不行。用 \(BFS\) 打了个表,发现后很多 \(n\) 答案是本身,看半天没看出来此时满足 \(n+1\) 是质数(唐完了兄弟)。然后后面就开摆了(草)。
补题
E
题目大意
在某场 ICPC 邀请赛,某支强队花费 0 分钟便阅读完了所有的 \(N\) 道题目。凭借丰富的比赛经验,他们瞬间想到了所有思路并且准确预估出了完成每道题所需要的时间,完成第 \(i\) 道题需要花费 \(T_i\) 分钟。
在比赛开始 0 分钟的时候,这只队伍开始编写所有题目。比赛罚时规则如下:如果你在第 \(t\) 分钟完成了一道题,那么总罚时会增加 \(t\)。
此时,这支队伍突然获得了一张时空回溯卡。通过合理使用这张卡片,他们也许能够逆转自己手速不足的劣势。卡片的使用规则如下:
- 卡片最多只能使用一次。你只能在比赛开始时(第 0 分钟)或恰好完成某一道题后的时刻使用它(也可以选择整场比赛都不使用)。
- 使用卡片后,当前比赛时间会立即减半。也就是说,如果你在第 \(X\) 分钟使用卡片,那么当前时间会瞬间回退到 \(X/2\) 分钟。
- 已经完成的题目状态不会改变,它们此前产生的罚时也会被保留。但之后完成的题目,将基于这个新的时间继续计算完成时刻与罚时。
队伍可以自由决定完成这 \(N\) 道题目的顺序,也可以自由决定在完成哪一道题之后使用卡片(假设切换题目与使用卡片均不消耗额外时间)。
比赛时间是无限的,无论如何这支队伍都可以写完所有的题目。请你计算,在最优策略下,完成所有题目的最小总罚时是多少。
思路
由于 \(n<=2000\),\(n^2\) 是可以接受的,我们对于每一个元素算一下贡献,不妨设在完成第 \(K\) 题之后使用回溯卡,第 \(i\) 题的时间为 \(t_i\),分两种情况讨论:
-
\(i>k\) 贡献为 \((n-k+1)*t_i\) 相当于被计算了 \(n-k+1\) 次。
-
\(i<=k\) 贡献为 \((k-i+1)*t_i+(n-k)*t_i/2\),相当于被计算了 \(n/2+k/2-i+1\) 次。
当我们确定了一个 \(k\) 我们可以求出每个位置 \(i\) 会被计算多少次,当确定了每个位置的计算次数后,我们就可以贪心地将用时少的题目匹配计算次数多的位置,这个操作可以通过排序实现,总复杂度为 \(O(n^2logn)\).
核心代码
for(double i=1;i<=n;i++){
for(double j=1;j<=n;j++){
if(j<=i){
q[(int)j]=n/2+i/2-j+1;
}else q[(int)j]=n-j+1;
}
sort(q+1,q+1+(int)n,greater<double>());
double sum=0;
for(int j=1;j<=n;j++){
sum+=q[j]*t[j];
}
ans=min(ans,sum);
}
I
题目大意
Bob 准备了 \(n + 1\) 枚硬币作为压岁钱送给 Alice。为了增加趣味性,他们决定玩一个游戏:
游戏开始时,Bob 拿出 1 枚硬币给 Alice。此时 Alice 手中有 1 枚硬币,Bob 手中有 \(n\) 枚硬币。
接下来,Alice 可以重复进行以下操作,直到拿走 Bob 手中的全部硬币:
- 假设当前 Alice 手中有 \(A\) 枚硬币,Bob 手中有 \(B\) 枚硬币。Alice 可以选择一个正整数 \(k\),满足 \(1 \le k \le \gcd(A, B)\),并将 \(k\) 枚硬币从 Bob 手中转移到自己手中。
其中 \(\gcd(A, B)\) 表示 \(A\) 与 \(B\) 的最大公约数。
请问 Alice 最少需要进行多少次操作,才能拿走 Bob 手中的全部硬币?
重要公式
\(gcd(A,B)=gcd(A,B-A)\)
思路
我们很容易会发现 \(A+B=n+1\) 是一个定值,所以只需要有一个值就可以确定最大公因数,即 \(gcd(A,B)=gcd(A,B+A)=gcd(A,n+1)\)
要让 \(A\) 在尽量少的步数内达到 \(n+1\),每次增加的上限为 \(gcd(A,n+1)\) 也就是说最大公因数越大前进越快,我们考虑 \(DP\) 来解决问题,设 \(dp[i]\) 表示达到第 \(i\) 个因数所需要的最少步数 $$dp_i = \min_{j<i}\left( dp_j + \frac{d_i-d_j}{d_j} \right)$$
从小到大转移即可,但是还有很重要的一点,已经因数如果存在另一个因数是它的倍数,任何比倍数大的因数都不会成为更优的选项,这很重要,这可以帮助我们减小很大的常数
核心代码
for(int i=0;i<d.size();i++){
for(int j=i+1;j<d.size();j++){
dp[j]=min(dp[j],dp[i]+(d[j]-1)/d[i]);
if(d[j]%d[i]==0)break;
}
}

浙公网安备 33010602011771号