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

Piggy343288
Where is my right path to go on.搬运于
2025-08-24 22:48:22,当前版本为作者最后更新于2023-06-23 11:18:28,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
首先我们考察 LIS 长度为 的数列的性质。可以发现,这必定是 中拎出一个不听话的元素甩到其他地方去,剩下的元素依次补齐所构成的。这意味着,最多只有一个元素满足 ,更具体的,不考虑只对邻项交换的排列(即形如 ),每个满足要求的排列都有且仅有一个元素满足 。
接下来对所有钦定了值的元素进行考察。这意味着下文中我们已经默认了 。
- 所有 。那么我们只能对下标的空隙部分做操作。也就是假设相邻的两个下标分别为 ,那么这一段对答案的贡献是 。不难写出如下的代码:
int cur = 0; for(int i = 1; i <= n; i++){ if(!~a[i]) cur++; else if(cur){ ans += pow(cur - 1, 2); cur = 0; } } if(cur) ans += pow(cur - 1, 2);- 存在 。因为这样的 只能有一个,所以如果找到多个这样的下标直接
cout<<0<<"\n"走人。即使仅有一个这样的 ,合法的也最多只能有一个排列。因此判断一下是否合法即可。不难写出下面的代码:
int p = -1; for(int i = 1; i <= n; i++){ if(!~a[i]) continue; if(abs(a[i] - i) >= 2){ if(~p) return false; else p = i; } } if(~p){ //found one abs(a[i] - i) >= 2 if(a[p] > p){ int l = p, r = a[p]; for(int i = 1; i <= n; i++){ if(!~a[i]) continue; if((i < l || i > r) && a[i] != i) return false; if((i > l && i <= r) && a[i] != i - 1) return false; } }else{ // just a reversion of a[p] > p... int l = a[p], r = p; for(int i = 1; i <= n; i++){ if(!~a[i]) continue; if((i < l || i > r) && a[i] != i) return false; if((i >= l && i < r) && a[i] != i + 1) return false; } } }- 存在 。这种比较好判断,而且也最多只能存在一个这样的 。
int cnt = 0; for(int i = 1; i <= n; i++){ if(a[i] != i && ~a[i]){ if(a[i] == i + 1 && a[i + 1] == i) i++, cnt++; else return false; } } if(!cnt) return false;在写代码的时候,我把上述两个情况合并在一起了。因为它和下面的情况相差较大,但这两个本质是一个情况,即指定了开头所提到的“不听话的元素”。
- 存在一段 或一段 。注意判断仅能存在一个这样的段!因此我们不难写出下面的代码,其中 标志了目前在什么阶段(进入段前,段中,第一段后)。
int flag = 0; p = 0; for(int i = 1; i <= n; i++){ if(!~a[i]) continue; if(a[i] == i){ if(flag == 1) flag = 2;// signal if i is out of the offset area. }else{ // a[i] != i r = i; if(flag == 0){ //no offset currently p = a[i] - i; l = i, flag = 1;// into the offset area; }else{ if(flag == 1){ if(a[i] - i != p) return false; }else{ assert(flag == 2); return false;// out of the offset area and found another section, // which is impossible to generate any valid solution in this occasion. } } } } return true;int lcnt = 0, rcnt = 0; for(int i = l - 1; i && !~a[i]; i--) lcnt++; for(int i = r + 1; i <= n && !~a[i]; i++) rcnt++; ans = 1ll * lcnt * rcnt; ans += (~p ? rcnt : lcnt);把几段代码融合一下,就得到了此题的代码。完整代码不给!
- 1
信息
- ID
- 8857
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者