一共是6道题目 主要以贪心 动态规划为重点 目前题解更新完前三道

清汤拉面

有一天下课,小泉同学、悠、美沙、润相约在一家学校附近的拉面馆。悠、美沙、润都点了清汤拉面。大家都知道,拉面店可以按自己喜好添加配菜,所以她们在面里加了一些叉烧猪肉。小泉发现,悠、美沙、润的碗里分别有$A,B,C$块叉烧猪肉。爱吃拉面的小泉同学希望她们能够吃到一样多的叉烧猪肉,店家提供了两种加配菜的方法:

  • 2个人的碗中分别加1块叉烧猪肉
  • 1个人的碗中添加2块叉烧猪肉

小泉同学想知道,最少需要加多少次配菜,能使朋友的碗中叉烧猪肉数量相同呢?

输入

输入包含多组数据

第一行包含一个第一行一个整数$T(1 \le T \le 10^3)$表示输入组数

每组数据一行三个整数$a,b,c(0 \le a,b,c \le 10^9)$,分别表示悠、美沙、润碗中的叉烧猪肉数量

输出

每组数据输出一个整数,表示最少的加配菜次数

样例输入

3

7 5 1

3 2 2

6 6 6

样例输出

4

1

0

数据范围

Subtask #分值$T$ 的限制$a, b, c$的限制
1$30$$T \le 10$$0 \le a,b,c \le 100$
2$30$$T \le 10^3$$0 \le a,b,c \le 10^6$
3$40$$T \le 10^3$$0 \le a,b,c \le 10^9$

解题思路

求出最大值*3-较小的两个 即为相差的块数能否被2整除,若不能则表明只给这两个较小的加来加去不能解决问题,否则表明可以

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>

using namespace std;

int main()
{
long long sum,Max,n,a,b,c,cha;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a>>b>>c;
sum=a+b+c;
Max=max(a,b);
Max=max(Max,c);
cha=(Max*3);
cha-=sum;
if (cha%2)
cout<<cha/2+2<<endl;
else
cout<<cha/2<<endl;
}
return 0;
}

小泉的数组

题目描述

小泉有一个长度为$n$的$01$串。对于这个串中的每一段连续子串,小泉有两种操作:

  1. 把一个子串左右颠倒,如:$011\to 110$

  2. 把一个子串的$01$互换,如:$000\to 111$

对于这两种操作,每做第一种操作的代价为$x$,每做后一种操作的代价为$y$

现在小泉想把一个串转换为全部为$1$,请问她所需要花费的最小代价为多少?

输入输出格式

输入格式

第一行三个整数$n, x, y$,$n$表示$01$串的长度,$x$表示第一种操作的代价,$y$表示后一种操作的代价。

第二行为一个长度为$n$的$01$串,表示需要转换的串。

保证$1 \le n \le 10^6, 1 \le x, y \le 10^3$。

输出格式

输出一行,包含一个整数,表示将该串转换为全为$1$的最小代价。

输入输出样例

输入样例1:

5 10 1

10010

输出样例1:

2

输入样例2:

6 2 3

101011

输出样例2:

5

说明

Subtask #分值$n$ 的限制$x, y$的限制
1$20$$n \leq 100$$x, y \leq 100$
2$20$$n \leq 10^4$$x, y \le 10^3$
3$60$$n \leq 10^6$$x, y \le 10^3$

解题思路:

首先 我们可以发现如果要执行第一种操作的话,必须只能执行一次第二种操作,因为如果一次一一次二会浪费很多,所以一共只有两种方式
1.将所有的0串一次一次的使用后者全部转为1
2.将所有的0串一次一次的使用第一种操作转为一整串0,然后1
比较两种的耗费 选择小的一种即可

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <string.h>

using namespace std;

char a[1000005];

int main()
{
int n,x,y,ans=0;
int t=0;
cin>>n>>x>>y;
cin>>a;
int len=strlen(a);
for (int i=0;i<len;i++)
{
if (a[i]=='0'){
int k=i;
while (a[k]=='0')k++;
for (int j=i;j<k;j++)
{
a[j]='1';
}
ans+=y;
t++;
}
}
cout<<min(x*(t-1)+y,ans);
return 0;
}

酱油拉面

悠为了在家给小泉同学做拉面,准备了$n$个面碗,这些面碗排成一线。她打算在每个面碗中都放入小泉同学爱吃的酱油拉面

由于拉面碗的正反面画上了一样的图案,粗心的悠将一些面碗弄反了。

为了使小泉能够顺利地吃到酱油拉面,她需要将这些的面碗翻转过来。然而,悠在翻转编号为$i$的面碗时,会使两边的,即编号为$i-1$和$i+1$的面碗也被翻转。

假设面碗的编号为$[1,n]$,当悠翻转最左边(编号为$1$)的面碗时,只有编号为$2$的面碗也被翻转;翻转最右边(编号为$n$)的面碗时,只有编号为$n-1$的面碗收到影响;当只有一个面碗时($n=1$),翻转动作只会作用于当前面碗。

悠很担心她能不能将所有的面碗翻正。如果能,悠想知道最少需要多少次翻转动作,以节约时间来制作美味的拉面呢?

输入

输入包含多组数据

第一行一个整数$T(1 \le T \le 100)$表示输入组数

每组数据第一行一个整数$n(1 \le n \le 10^5 )$,表示面碗的数量。数据保证$\sum n \le 10^6$

接下来一行包含$n$个数字,其中第$i$个数字$a_i$为0时,表示面碗是正的;当$a_i$为1时,表示面碗是反的

输出

对于每一组数据,如果悠不能将翻转所有的面碗,输出一行Sad Yuu

否则输出悠最少需要翻转的次数

##样例输入

2

5

0 1 0 1 1

8

0 1 1 0 1 0 1 1

样例输出

Sad Yuu

3

Subtask #分值$T$ 的限制$\sum{n}$ 的限制
1$15$$T=2$$\sum{n} \leq 20$
2$15$$T \leq 10$$\sum{n} \leq 10^3$
3$20$$T \leq 100$$\sum{n} \leq 10^5$
4$50$$T \leq 100$$\sum{n} \leq 10^6$

解题思路:

看到1就翻他后一个
然后从新的优化过的数组再扫一遍
输出更少的步数即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>

using namespace std;

bool a[100005],b[100005];

int main()
{
int t,n;
cin>>t;
while (t--)
{
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>a[i];
}
if (n==1)//特殊情况考虑
{
if (a[1]==1) cout<<1<<endl;
if (a[1]==0) cout<<0<<endl;
continue;
}
int ans1=0,ans2=0;
for (int i=n;i>=1;i--)
b[i]=a[i];
b[1]=!b[1];b[2]=!b[2];ans2++;//优化前两个 以免出现 1 1 式后面判断为Sad Yuu

for (int i=1;i<n;i++)
{
if (a[i])//有一就直接翻他后面一个
{
a[i]=!a[i];
a[i+1]=!a[i+1];
a[i+2]=!a[i+2];
ans1++;
}
}
for (int i=1;i<n;i++)//重新做一遍 防止卡1 1
{
if (b[i])
{
b[i]=!b[i];
b[i+1]=!b[i+1];
b[i+2]=!b[i+2];
ans2++;
}
}
int f1=0,f2=0;
for (int i=1;i<=n;i++)//判断是否反转成功
{
f1+=a[i];
f2+=b[i];
}
//输出
if (f1==0 && f2==0) cout<<min(ans1,ans2)<<endl;
if (f1==0 && f2!=0) cout<<ans1<<endl;
if (f1!=0 && f2==0) cout<<ans2<<endl;
if (f1!=0 && f2!=0) cout<<"Sad Yuu"<<endl;
}
return 0;
}

四汉诺塔

问题背景

汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。传说中,大梵天创造世界的时候做了三根金刚石柱子,在一根柱子从下往上按照大小顺序摞着$64$片黄金圆盘,大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘

题目描述

小泉对于普通的三柱汉诺塔问题已经十分熟悉了,对于$n$个圆盘的汉诺塔问题,最少需要的移动次数为
$$
f(n) = 2^n -1
$$
小泉很好奇的是,对于有多个柱子的汉诺塔问题来说,最少的移动次数为多少?

由于小泉觉得$m$柱汉诺塔问题,当$m \geq 5$时对你来说太难了,所以你只需要回答当$m=4$时,将$n$个圆盘从第一根柱子移动到另一根柱子的最少移动次数。

因为这个数可能会比较大,所以小泉只需要你输出对$1000000007(10^9+7)$取模的结果即可。

输入输出格式

输入格式

包含多组输入

第一行一个整数$T$,表示输入组数。

接下来$T$行,一行一个整数$n$,表示圆盘的数量。

保证$1 \le T \le 10^3, 1 \le n \le 10^3$。

输出格式

输出$T$行,每行一个整数,表示将$n$个圆盘移动到另一根柱子的最少移动次数对$1000000007(10^9+7)$取模的结果。

输入输出样例

输入样例1:

3

2

6

10

输出样例1:

3

17

49

说明

Subtask #分值$T$ 的限制$n$的限制
1$20$$1$$n \leq 10$
2$20$$T \leq 10$$n \leq 50$
3$20$$T \leq 100$$n \le 100$
4$20$$T \le 10^3$$n \le 10^3$
5$20$$T \le 10^3$$n \le 10^6$

评论