题解 CF23B 【Party】

Mars_Dingdang

2020-11-15 15:35:11

Solution

双倍经验:P1416 攻击火星(用户名叫 Mars 的我有被冒犯额)。因此,本题显然恶评了。 ## 题目大意 现在聚会上有 $n$ 个人参加,然后依次按照规律离开,第一次是有 $0$ 个朋友的人离开,第二次是有 $1$ 个朋友的人离开,第三次是有 $2$ 个朋友的人离开,之后依次是有 $3,4,5,6\cdots n-1$ 个朋友的一次离开,求最后聚会最多将会剩下多少人。 可以抽象为:一个 $n$ 个点的无向图, 先攻击度为 $0$ 的点(相当于从图中删除掉它),然后是度为 $1$ 的点,依此类推直到度为 $n-1$ 的点。 所有的点度统计是动态统计的。(一个点删掉后,与之相连的点的点度都会 $-1$)。攻击度为某个数的点时是同时攻击的。 你需要设计这个图的边的方案来使得未被攻击的点最多。 ## 大体思路 首先观察到 P1416 数据范围 $n\le 50000$,无法直接用邻接表,意味着这可能是一道结论题。 那么我们来找规律 + 构造。 - 当 $n=1,2$ 时,显然所有点均会被删去,$ans=0$。 - 当 $n=3,4$ 时,可以保留一个点。P1416 的样例使用的是类似链的构造 ①-②-③。 - 当 $n=5$ 时,按链构造会出现问题:即删去两端结点后,中间结点度为 $2$,仍会被删去。因此,构造法变为:选出两个末端节点,把两个末端节点与所有非末端节点相连,再把非末端节点与所有非末端节点相连。 ![](https://cdn.luogu.com.cn/upload/image_hosting/ma64npnu.png) 因此,特判 $n=1$ 时 $ans=0$,否则 $ans=n-2$。 ## 完整代码 ```cpp #include<bits/stdc++.h>//cpp using namespace std; int main(){ int t; cin>>t; while(t--){ long long n; cin>>n; if(n==1) cout<<0;//特判 else cout<<n-2; puts(""); } return 0; } ``` 相比之下,python 就短了很多: ```python t=int(input())//python while t>0: a=int(input()) if a == 1: print(0)//特判 else print(a-2) t -= 1 ``` ## 后记 1. python 中 `input()` 函数默认输入字符串,因此需要强制类型转换 `int(input())`; 2. python 缩进相当于大括号; 3. t-=1 不能写成 t--。 更多技巧详见 LucasXu80 [博客](https://www.luogu.com.cn/blog/HuayuLucas/python-kuai-su-shang-shou)。