• AcWing第20场周赛总结


    3994. 水果派

    题目链接:

    https://www.acwing.com/problem/content/3997/

    1. 题目描述

    食堂需要做至少 a 份苹果派和至少 b 份香蕉派。

    已知,一个苹果可以做 c 份苹果派,一个香蕉可以做 d 份香蕉派。

    食堂共可以采购不超过 k 个水果。

    请提供一种食堂采购水果的方案,以满足制作水果派的需求。

    输入格式

    第一行包含整数 T,表示共有 T组测试数据。

    每组数据占一行,包含 5 个整数 a,b,c,d,k。

    输出格式

    每组数据输出一行结果,如果存在合理方案,则输出两个整数 x,y,表示需要采购的苹果和香蕉数量。

    如果不存在合理方案,则输出 −1。

    任意合理方案均可。

    数据范围

    前三个测试点满足,1≤T≤1。
    所有测试点满足,1≤T,a,b,c,d,k≤100。

    输入样例:

    3
    7 5 4 5 8
    7 5 4 5 2
    20 53 45 26 4
    

    输出样例:

    7 1
    -1
    1 3
    

    2. 思路及题解

    思路:

    k个水果(可以是苹果,也可以是香蕉)做a份苹果派和b份香蕉派。

    其中1个苹果可以做c份苹果派,1个香蕉可以做d份香蕉派。

    则可以转化为不等式:

    [lceilfrac{a}{c} ceil+lceilfrac{b}{d} ceil≤k ]

    应知应会:

    • (lceil ceil)表示浮点数向上取整,例:3.23,向上取整后为3;-1.56向上取整后为-1。

      C++中向上取整的函数为ceil(),头文件为<cmath>

    • 延伸:(lfloor floor)表示浮点数向下取整。

      C++中向下取整的函数为floor(),头文件为<cmath>

    题解:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    
    using namespace std;
    
    int T, a, b, c, d, k;
    
    int main()
    {
    	cin >> T;
    	while (T--) 
    	{
    		cin >> a >> b >> c >> d >> k;
    		int x = ceil(1.0 * a / c); 
    		int y = ceil(1.0 * b / d);
    		// 这里如果a/c + b/d <=k,说明满足条件,否则表明水果数量不够 
    		if (x + y <= k) cout << x << " " << y << endl;
    		else cout << -1 << endl;
    	}
    	return 0;
    } 
    

    3995. 最小的和

    题目链接:

    https://www.acwing.com/problem/content/3998/

    1. 题目描述

    给定两个长度为 n 的整数序列 a1,a2,…,an 和 b1,b2,…,bn。

    现在要对序列 a 进行恰好 k1 次操作,对序列 b 进行恰好 k2 次操作。

    每次操作具体流程为选取序列中的一个元素,并将其加 1 或减 1。

    要求所有操作进行完毕以后,(sum_{i=1}^{n}(ai−bi)^2)尽可能小。

    输入格式

    第一行包含三个整数 n,k1,k2。

    第二行包含 n 个整数 a1,a2,…,an。

    第三行包含 n 个整数 b1,b2,…,bn。

    输出格式

    一个整数,表示所有操作进行完毕以后,(sum_{i=1}^{n}(ai−bi)^2)的最小可能值。

    数据范围

    前六个测试点满足,1≤n≤5。
    所有测试点满足,(1≤n≤10^{3})(0≤k1+k2≤10^{3}),k1 和 k2 都是非负整数,(−10^{6}≤ai,bi≤10^{6})

    输入样例1:

    2 0 0
    1 2
    2 3
    

    输出样例1:

    2
    

    输入样例2:

    2 1 0
    1 2
    2 2
    

    输出样例2:

    0
    

    输入样例3:

    2 5 7
    3 4
    14 4
    

    输出样例3:

    1
    

    2. 思路及题解

    思路:

    1. 首先是数据初始化:n,k1,k2,数组a,数组b。
    2. 初始化数据后,将|a[i] - b[i]|的值存入sub[i]。
    3. 对sub数组进行正序排序。
    4. 开始做加减法。这里考虑一个问题:因为k1次数是对a数组操作,k2数组是对b数组操作,每次操作都是加1或者减1,而操作的最终目的是为了让|a[i]-b[i]|尽可能的小,即我们是要用k1+k2次数操作使|a[i]-b[i]|尽可能小,本质上就是要对sub数组进行操作就可以了。再考虑sub数组中最大值因为开平方后,数值肯定是大于较小的数,所以我们每次操作的时候先对sub数组中最大值进行操作,每次操作选择sub数组中的最大值并减1,这样可以让整体的平方和更小。但是有例外,就是当sub数组中最大值为0时,此时如果还有剩下的操作次数,我们可以依次对最大值0进行+1、-1操作,即最终的平方和要么为0,要么为1
    5. 经过上面分析,就知道了为什么要对sub数组进行排序了,这样方便我们每次寻找最大值。每进行一次操作,就遍历一次sub数组,一开始遍历时,先记录下最大值max,即sub最后一个数值。当遍历到sub[j]为max时(注意最大值不一定只有一个,即此时遍历不一定到sub最后一个数),对sub[j]做-1操作,即让|a[i]-b[i]|减小。
    6. 如果操作次数足够多,就会出现操作到最后sub数组中的值都为0,则此时就只对0进行依次+1、-1操作。即如果剩余次数为奇数,则最终结果为1;如果为偶数,则结果为0.

    Q&A:

    Q1:这题怎么确定两层训话不会超时?

    A1:下面解法的时间复杂度为O((k1+k2)*n),计算机1秒大概可以进行1亿次操作(1,0000,0000)。而k1和k2最大值为1000,n的最大值为1000,所以(k1 + k2) * n的最大值为200,0000,远没有1亿次那么多,所以肯定不会超时!

    题解:

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    typedef long long ll;
    
    ll n, k1, k2;
    ll a[1005], b[1005];
    ll sub[1005];
    
    int main()
    {
    	cin >> n >> k1 >> k2;
    	for (int i = 0; i < n; ++i)
    		cin >> a[i];
    	ll s = 0;
    	for (int i = 0; i < n; ++i)
    	{
    		cin >> b[i];
    		// sub[i] = |a[i] - b[i]| 
    		sub[i] = (a[i] - b[i] > 0) ? a[i] - b[i] : b[i] - a[i];
    	}
    	// 总共进行k1 + k2次操作 
    	ll k = k1 + k2;
    	sort(sub, sub + n);
    	int max = sub[n - 1];
    	
    	for (int i = 0; i < k; ++i)
    	{
    		max = sub[n - 1];	// 记录下此时sub数组中的最大值 
    		if (max == 0)		// 即此时sub数组中的值都为0 
    		{
    			if ((k - i) % 2 == 1)	// 剩余操作次数为奇数,结果为1 
    				cout << 1 << endl;
    			else 
    				cout << 0 << endl;	// 剩余操作次数为偶数,结果为0 
    			return 0;
    		}
    		for (int j = 0; j < n; ++j)
    		{
    			if (sub[j] == max)	// 找到sub数组中的最大值,并对其进行-1操作 
    			{
    				sub[j]--;
    				break;
    			}
    		}
    	}
    	ll sum = 0;
    	for (int i = 0; i < n; ++i)	// 求解平方和 
    		sum += sub[i] * sub[i];
    	cout << sum << endl;
    	return 0;
    } 
    

    3996. 涂色

    题目链接:

    https://www.acwing.com/problem/content/3999/

    1. 题目描述

    有 n 个砖块排成一排,从左到右编号为 1∼n。

    其中,第 i 个砖块的初始颜色为 ci。

    我们规定,如果编号范围 [i,j] 内的所有砖块的颜色都相同,则砖块 i 和 j 属于同一个连通块。

    例如,[3,3,3] 有 1 个连通块,[5,2,4,4] 有 3 个连通块。

    现在,要对砖块进行涂色操作。

    开始操作前,你需要任选一个砖块作为起始砖块

    每次操作:

    1. 任选一种颜色。
    2. 起始砖块所在连通块中包含的所有砖块都涂为选定颜色,

    请问,至少需要多少次操作,才能使所有砖块都具有同一种颜色。

    输入格式

    第一行包含整数 n。

    第二行包含 n 个整数 c1,c2,…,cn。

    输出格式

    一个整数,表示所需要的最少操作次数。

    数据范围

    前六个测试点满足,1≤n≤20。
    所有测试点满足,1≤n≤5000,1≤ci≤5000。

    输入样例1:

    4
    5 2 2 1
    

    输出样例1:

    2
    

    输入样例2:

    8
    4 5 2 2 1 3 5 5
    

    输出样例2:

    4
    

    输入样例3:

    1
    4
    

    输出样例3:

    0
    

    2. 思路及题解

    待填坑。。。未完待续

  • 相关阅读:
    ASPNET下的路径辅助类
    分析函数计算起始,结束日期.
    Debugging SQL Server 2005 Stored Procedures in Visual Studio
    Storing Binary Files Directly in the Database Using ASP.NET 2.0
    Fw:Managing View State in ASP.NET 4 Using the New ViewStateMode Property
    Using ASP.NET 3.5's ListView and DataPager Controls: Displaying Data with the ListView
    Passing Information Between Content and Master Pages .
    转:Querying a Hierarchical ParentChild Structure in LINQ
    续上篇:比较彻底的清除"代理木马下载器"的方法
    面向过程和面向对象--从C到C#
  • 原文地址:https://www.cnblogs.com/vanishzeng/p/15388297.html
Copyright © 2020-2023  润新知