2021.10.30 JXNU ACS算法组 周练部分题解

A Vupsen, Pupsen and 0

描述:

Vupsen and Pupsen were gifted an integer array. Since Vupsen doesn't like the number 0, he threw away all numbers equal to 0 from the array. As a result, he got an array a of length n.

Pupsen, on the contrary, likes the number 0 and he got upset when he saw the array without zeroes. To cheer Pupsen up, Vupsen decided to come up with another array b of length n such that \small \sum_{i=1}^na_i\cdot b_j=0. Since Vupsen doesn't like number 0, the array b must not contain numbers equal to 0. Also, the numbers in that array must not be huge, so the sum of their absolute values cannot exceed \small 10^9. Please help Vupsen to find any such array b!

输入:

The first line contains a single integer t (1≤t≤100) — the number of test cases. The next 2⋅t lines contain the description of test cases. The description of each test case consists of two lines.

The first line of each test case contains a single integer n (2≤n≤\small 10^52≤n≤\small 10^5) — the length of the array.

The second line contains n integers a1,a2,…,an (−\small 10^4≤ai≤\small 10^4\small 10^4≤ai≤\small 10^4, ai≠0ai≠0) — the elements of the array a.

It is guaranteed that the sum of n over all test cases does not exceed \small 2\cdot 10^5.

输出:

For each test case print n integers b1,b2,…,bn — elements of the array b (|b1|+|b2|+…+|bn|≤\small 10^9, bi≠0, \small \sum_{i=1}^na_i\cdot b_j=0).

It can be shown that the answer always exists.

样例输入:

3
2
5 5
5
5 -2 10 -9 4
7
1 2 3 4 5 6 7

样例输出:

1 -1
-1 5 1 -1 -1
-10 2 2 -3 5 -1 -1

注释:

In the first test case, 5⋅1+5⋅(−1)=5−5=0. You could also print 3 −3, for example, since 5⋅3+5⋅(−3)=15−15=0

In the second test case, 5⋅(−1)+(−2)⋅5+10⋅1+(−9)⋅(−1)+4⋅(−1)=−5−10+10+9−4=0.

分析题目:

题目简单用中文说就是,我给了你一个数组a其中不含有0,让你输出一个数组b同样不含0,你要实现ai*bi加和等于0。就此我们可以知道,b数组不一定唯一,所以不要被样例输出骗了。

解题思路:

我们想,要让最后a,b数组对应乘积的和为0,假设我们现在a数组只有两个,那么b数组怎么确定最快呢?a1*b1+a2*b2=0,是不是很像另一个公式,x1*y2-x2*y1=0,我们模仿着来,a1*a2-a1*a2=0,所以b1=a2,b2=-a1.这不就是最快的方法吗

但是我们得到的a数组不可能就2个,那么我们推广一下,假如n是偶数,我们可以把a数组分成n/2个小组,每个小组都用这个方法,这样就可以保证a数组每个都有对应,

那如果n是奇数呢?

我们只要让一个组是三个其他的还是两个就可以了,那三个的一组还可以再分,将1,2,3变成1+2,3或1+3,2或1,2+3这三组再用刚才的方法判断就可以了。

代码示例:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int t;
int n;
int a[101010];

int main(){
	cin>>t;
	while(t--){
		memset(a,0,sizeof(a));
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		if(n%2==0){
			for(int i=1;i<=n;i+=2) cout<<-a[i+1]<<" "<<a[i]<<" ";	
			cout<<endl;
			continue;
		} 
		else{
			if(a[1]+a[2]) cout<<a[3]<<" "<<a[3]<<" "<<-(a[1]+a[2])<<" ";
			else if(a[2]+a[3]) cout<<-(a[2]+a[3])<<" "<<a[1]<<" "<<a[1]<<" ";
			else if(a[1]+a[3])cout<<a[2]<<" "<<-(a[1]+a[3])<<" "<<a[2]<<" ";
			for(int i=4;i<=n;i+=2) cout<<-a[i+1]<<" "<<a[i]<<" ";
			cout<<endl;
		}
	}
}

D 改革春风吹满地

描述:

“ 改革春风吹满地,
不会AC没关系;
实在不行回老家,
还有一亩三分地。
谢谢!(乐队奏乐)”

话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也是云里雾里,而且,还竟然来这么几句打油诗。
好呀,老师的责任就是帮你解决问题,既然想种田,那就分你一块。
这块田位于浙江省温州市苍南县灵溪镇林家铺子村,多边形形状的一块地,原本是linle 的,现在就准备送给你了。不过,任何事情都没有那么简单,你必须首先告诉我这块地到底有多少面积,如果回答正确才能真正得到这块地。
发愁了吧?就是要让你知道,种地也是需要AC知识的!以后还是好好练吧...

输入:

输入数据包含多个测试实例,每个测试实例占一行,每行的开始是一个整数n(3<=n<=100),它表示多边形的边数(当然也是顶点数),然后是按照逆时针顺序给出的n个顶点的坐标(x1, y1, x2, y2... xn, yn),为了简化问题,这里的所有坐标都用整数表示。
输入数据中所有的整数都在32位整数范围内,n=0表示数据的结束,不做处理。

输出:

对于每个测试实例,请输出对应的多边形面积,结果精确到小数点后一位小数。
每个实例的输出占一行。

样例输入:

3 0 0 1 0 0 1
4 1 0 0 1 -1 0 0 -1
0

样例输出:

0.5
2.0

分析题目:

给你坐标,你要求出这几个坐标点围成的面积。

解题思路:

我们肯定不能直接求一个多边形的面积,但我们可以用分割法,我们把所有点,按顺序链接起来,一共有n条边,我们用这几个三角形求和就可以了,而且我们有每个坐标的点,我们取出两个相邻的点(x1,y1)(x2,y2),用向量求面积的方法,abs(x1*y2-x2*y1)/2 加和起来就可以了

代码示例:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;

int n,t;
double sum;
double X[100010],Y[100010];

double get_s(double x,double y,double a,double b){
	return x*b-a*y;
}

int main(){
	while(1){
		sum=0;
		memset(X,0,sizeof(X));
		memset(Y,0,sizeof(Y));
		cin>>n;
		if(n==0) break;
		for(int i=1;i<=n;i++) cin>>X[i]>>Y[i];
		X[n+1]=X[1];
		Y[n+1]=Y[1];
		for(int i=1;i<=n;i++){
			sum+=abs(get_s(X[i],Y[i],X[i+1],Y[i+1]));
		}
		sum/=2;
		printf("%.1lf\n",sum);
	}
	return 0;
}

 Maximum Cost Deletion

描述:

You are given a string s of length n consisting only of the characters 0 and 1.

You perform the following operation until the string becomes empty: choose some consecutive substring of equal characters, erase it from the string and glue the remaining two parts together (any of them can be empty) in the same order. For example, if you erase the substring 111 from the string 111110, you will get the string 110. When you delete a substring of length l, you get a⋅l+bpoints.

Your task is to calculate the maximum number of points that you can score in total, if you have to make the given string empty.

输入:

The first line contains a single integer t (1≤t≤2000) — the number of testcases.

The first line of each testcase contains three integers n, a and b (1≤n≤100;−100≤a,b≤100) — the length of the string s and the parameters a and b.

The second line contains the string s. The string s consists only of the characters 0 and 1.

输出:

For each testcase, print a single integer — the maximum number of points that you can score.

样例输入:

3
3 2 0
000
5 -2 5
11001
6 1 -4
100111

样例输出:

6
15
-2

注释:

In the first example, it is enough to delete the entire string, then we will get 2⋅3+0=6points.

In the second example, if we delete characters one by one, then for each deleted character we will get (−2)⋅1+5=3 points, i. e. 15 points in total.

In the third example, we can delete the substring 00 from the string 100111, we get 1⋅2+(−4)=−2 points, and the string will be equal to 1111, removing it entirely we get 1⋅4+(−4)=0 points. In total, we got −2 points for 2 operations.

分析题目:

给T,给T组数据输入,每组数据中带有一个n、a、b,以及一个长度为n的只有 ‘ 0和1 ’ 构成的串,我们
可以选定 连续相同子串(尤为注意长度可以为1)消除并获得 : L(删去的长度) * a + b的分数,剩下
的自动补齐。
例如:串为001100,你可以选定中间 ‘11’ 子串并删去,获得: a * 2(‘11’串的长度) + b的分数,然后
原串变成 ‘ 0000 ’ 继而选中剩下的全部,分数再加上 : a * 4 + b 的分数

解题思路:

对于给定的 公式 a * L + b, L 是每次操作删去的长度,对于所有的操作总删去的长度是n(字符串的长
度)也就是说 a * L 是固定的
然后加上b 操作的次数 最后我们可以得到这样的一组公式: 分数 = a 总长度 + b * 操作次数
很明显 分数和b挂钩 进分类讨论
1) 当b大于等于0的时 操作次数越多越好 也就是进行 n 次操作 分数 = a n + b n = (a + b) * n;
2) 当b小于0时 操作数应越少越好 那我们可以统计连通块‘0’ 和 ‘1’的个数 count_0 和 count_1;
比如 : 0110001110000110
1 的连通块数是 3 , 0 的连通块数是 4
然后我们先把小的连通块数删掉 最后在删掉 连通块大的那个 总的操作数是 min(count_0,
count_1) + 1;

代码示例:

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int t;
int n,a,b;
int ans0,ans1;
string s;

int main(){
	cin>>t;
	while(t--){
		cin>>n>>a>>b;
		cin>>s;
		if(b>=0) cout<<a*n+b*n<<endl;
		if(b<0){
			ans1=ans0=0;
			int last;
			last=s[0];
			if(last=='0') ans0++;
			if(last=='1') ans1++;
			for(int i=1;i<=n;i++){
				if(s[i]!=last){
					last=s[i];
					if(s[i]=='1') ans1++;
					if(s[i]=='0') ans0++;
				}
			}
			cout<<a*n+(min(ans1,ans0)+1)*b<<endl;
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值