1 条题解
-
0
自动搬运
来自洛谷,原作者为

VainSylphid
美しい音色で世界が鳴った搬运于
2025-08-24 23:06:58,当前版本为作者最后更新于2024-12-16 10:21:53,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
upd on 2024.12.20:修正了次数上界的错误,修改了代码中的错误,感谢 rizynvu 的指正。
双倍经验:CF2038B。
观察到当 时,我们必须通过汇款使得 才可能有解,不妨先做尽可能多的操作使得 。特别的,当 时,因为你不能让 变成负的,所以降到 就暂时不能再降了。
我们从 开始,执行这个汇款操作足够多次,直到不能操作为止,然后判断是否有所有的 成立。这样看上去特别对,但是不太好证。一个感性的理解就是,如果有解,相邻两个位置之间汇款的次数是唯一确定的,而这样操作保证了每个位置不会超过次数的上界,因此不会提前把自己卡死,同时肯定在所有位置都达到上界之前一定存在一个位置可以继续调整,也就一定能调整出解。
然后我们考虑需要调整多少轮。考虑我们执行一圈以后,几乎所有多余的数都被推到了一个位置上,对于其他位置,若 ,有 或 ;否则 ,有 或 。考虑这个位置的 ,设为 ,且 是所有 的最大值。当 时,每在 处做一次操作, 都会减小,变成一个不超过 的值,因此做 轮后我们能得到 。此时有一种特殊的情况,即当前 ,下一个位置刚好满足 ,这个时候做一次操作 不变。但是不可能一直出现这样的情况,至多再转一圈就会停下来。综上,我们只需要执行一圈,多做 次,再执行一圈,就一定能调整完。
注意,由于 可能小于 ,在设置循环次数时应当设为 ,其中 是足够大的常数,其下界在上文已经做过分析。时间复杂度 。
#include<bits/stdc++.h> #define ll long long using namespace std; int n,a[1000005],b[1000005]; int main() { scanf("%d",&n); for(int i = 0;i < n;i++) { int x,y; scanf("%d%d",&x,&y); a[i] = x - y; if(!y) b[i] = 1; } for(int i = 0;i < n * 2 + 50;i++) { int p = i % n,q = (i + 1) % n; if(a[p] < 0) continue; int tmp = (a[p] + 1) / 2; if(b[p]) tmp = a[p] / 2; a[q] += tmp,a[p] -= tmp * 2; } for(int i = 0;i < n;i++) if(a[i] != 0) { printf("No\n"); return 0; } printf("Yes\n"); return 0; }
- 1
信息
- ID
- 11115
- 时间
- 1000ms
- 内存
- 250~512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者