Editorial of CodeTON Round 4 (Div. 1 + Div. 2, Rated, Prizes!)部分题解(A-D)

目录

A. Beautiful Sequence

题意:

题解:

代码:

B. Candies

题意:

题解:

代码:

C.Make It Permutation

题意:

题解:

代码:

D.Climbing the Tree

题意:

题解:

代码:


A. Beautiful Sequence

题意:

题目要求判断一个序列是否是“美丽的”。一个序列是“美丽的”,当且仅当它至少有一个子序列是“好的”。一个序列是“好的”,当且仅当至少有一个元素等于它的下标。例如,[4,3,2] 是一个“美丽的”序列,因为它的子序列 [4,2] 是“好的”。而 [5,3,4] 不是一个“美丽的”序列。

题解:

如果原数组中某个位置的数,小于等于它的下标i(从1开始),那数组就能去掉前面部分,让他满足条件。

代码:

 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #define ll long long
 #define inf 0x3f3f3f3f
 using namespace std;
 ​
 inline ll read() {ll x = 0, z = 1;char c = getchar();while (!isdigit(c)) {if (c == '-')z = -1;c = getchar();}while (isdigit(c)) {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return z * x;}
 inline void writ(ll x){if(x<0) {putchar('-');x=(~x)+1;}if(x>9)writ(x/10);putchar(x-x/10*10+48);}
 const int N=100010;
 ​
 int main(int argc, char *argv[])
 {
     //ios::sync_with_stdio(false);
     //cin.tie(0);
     ll t=read();
     while(t--){
         ll n=read();
         int flag=0;
         for (int i = 1; i <= n; i++)
         {
             if(read()<=i)flag=1;
         }
         if(flag)cout<<"YES"<

B. Candies

题意:

给定一个整数 n,你需要构造一个序列,使得从 1 开始,每次乘以 2 再加上或减去 1,最终得到 n。你最多可以进行 40 次操作。

你不需要最小化 m,如果有多个解,你可以输出任意一个。

如果不可能得到 n,输出一行 -1。

题解:

对1操作能到达的数是固定的,搜索出来的复杂度有2^40,太大了。但自己画几层搜索树就发现,最下面一层的数是1,3,5,... ,2^40+1

而且从相邻两层看,1在左子树,3在右,5在左,即(x+1)/2是奇数在左子树上,需要-1实现,反之偶数需要加1。

用栈从下往上保存输出。

代码:

 
#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #define ll long long
 #define inf 0x3f3f3f3f
 using namespace std;
 ​
 inline ll read() {ll x = 0, z = 1;char c = getchar();while (!isdigit(c)) {if (c == '-')z = -1;c = getchar();}while (isdigit(c)) {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return z * x;}
 inline void writ(ll x){if(x<0) {putchar('-');x=(~x)+1;}if(x>9)writ(x/10);putchar(x-x/10*10+48);}
 const int N=100010;
 ​
 int main(int argc, char *argv[])
 {
     //ios::sync_with_stdio(false);
     //cin.tie(0);
     ll t=read();
     stackans;
     while(t--){
         ll n=read();  
         if(n&1){
             while(n!=1){
                 if(((n+1)/2)&1){ans.push(1);n=(n+1)/2;}
                 else {ans.push(2);n=(n-1)/2;}
             }
             cout<

C.Make It Permutation

题意:

题目给出一个长度为 n 的整数数组 a,你可以进行两种操作:

  1. 从 a 中删除一个整数,这个操作的代价为 c。

  2. 在 a 的任意位置插入一个正整数 x,这个操作的代价为 d。

你的目标是通过这些操作,使得最终的数组是一个任意长度的排列。

[2,3,1,5,4] 是一个排列,但 [1,2,2] 不是排列(2 在数组中出现了两次),[1,3,4] 也不是排列(n=3 但数组中有 4)。

输出使最终数组成为排列所需的最小代价。

题解:

相同的数一定需要删掉多余的,我们就得到了一组从小到大的数列。

显而易见,我们最好选择一个位置,删去后面部分而补全前面部分,代价就随我们的选的位置发生变化,是一个离散的函数。

然后我就下意识以为中间肯定是最小值,写了三分,错了。

代价函数是这样的:f(pos)=(pos-cnt)*d+(n-cnt)*c,其中pos是选的位置,cnt是pos前面保留数的个数,显而易见,前面随着pos增大而增大,后面减小。我们不能确定它的趋势。

但我们知道,这个于数组有关的函数,在数组的两个相邻的数之间的变化趋势是可以预测的(贪心),这里显然我们不能把pos选在两个数之间,所以我们可以直接暴力找到最小值,复杂度n。

代码:

 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #define ll long long
 #define inf 0x3f3f3f3f
 using namespace std;
 ​
 inline ll read() {ll x = 0, z = 1;char c = getchar();while (!isdigit(c)) {if (c == '-')z = -1;c = getchar();}while (isdigit(c)) {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return z * x;}
 inline void writ(ll x){if(x<0) {putchar('-');x=(~x)+1;}if(x>9)writ(x/10);putchar(x-x/10*10+48);}
 const int N=100010;
 ​
 setst;
 ll n,c,d;
 // ll f(int x){
 //     int pos=*--upper_bound(st.begin(),st.end(),x);
 //     int cnt = distance(st.begin(), st.upper_bound(x));
 //     cout< f(mid2)) l = mid1 + 1;
 //         else r = mid2 - 1;
 //     }
 //     return f(l);
 // }
 ​
 int main(int argc, char *argv[])
 {
     //ios::sync_with_stdio(false);
     //cin.tie(0);
     ll t=read();
     while(t--){
         set().swap(st);
         n=read(),c=read(),d=read();
         for (int i = 0; i < n; i++)
         {
             int x=read();
             st.insert(x);
         }
         //cout<

D.Climbing the Tree

题意:

题目描述了一些蜗牛爬树的过程。树的高度为 h 米,蜗牛从位置 0 开始爬。

每只蜗牛有两个属性 a 和 b (a>b)。从第 1 天开始,一只蜗牛这样爬树:白天,它向上爬 a 米;晚上,蜗牛休息,它下滑 b 米。如果在第 n 天,蜗牛第一次到达位置 h(即树顶),它将完成攀爬,我们说蜗牛花了 n 天爬树。注意,在最后一天攀爬时,蜗牛不一定向上爬 a 米,以防它到顶部的距离小于 a。

不幸的是,你一开始并不知道确切的树高 h,但你知道 h 是一个正整数。有 q 个事件,分为两种类型。

  1. 类型 1 的事件:一只具有属性 a、b 的蜗牛来了,并声称它花了 n 天爬树。如果这条消息与先前采纳的信息相矛盾(即不存在一棵树使所有先前采纳的陈述和这一条都成立),则忽略它。否则,采纳它。

  2. 类型 2 的事件:一只具有属性 a、b 的蜗牛来了,并询问你如果他爬树会花费多少天。你只能根据迄今为止采纳的信息给出答案。如果你无法确定答案,请报告。

你需要按顺序处理所有事件。 输入包括多组测试数据。

题解:

显而易见的模拟,要注意前一天他最高到过(a-b)*(n-2)+a,而不是(a-b)*(n-1)

代码:

emmmm,还在debug

你可能感兴趣的:(算法,数据结构,servlet)