Codeforces Round 892 (Div. 2)
目录
- A. United We Stand
- 题目大意
- 思路
- 代码
- B. Olya and Game with Arrays
- 题目大意
- 思路
- 代码
- C. Another Permutation Problem
- 题目大意
- 思路
- 代码
A. United We Stand
题目大意
给你一个数组,把这个数组分成两个数组a和b,使得数组a任意一个数都不是数组b内任意一个数的倍数
翻译:
给定一个长度为n的数组a,包含整数。并且有两个初始为空的数组b和c。您需要将数组a的每个元素恰好添加到数组b或c中的一个,以满足以下条件:
数组b和c都是非空的。更正式地说,设lb为数组b的长度,lc为数组c的长度,则lb,lc≥1。对于任意两个指标i
j(1≤i≤lb,1≤j≤lc) cj不是bi的约数。输出可查询到的数组b和c,如果不存在则输出−1。输入 每个测试由多个测试用例组成。第一行包含一个整数t(1≤t≤500)——测试用例的数量。下面是测试用例的描述。
每个测试用例的第一行包含一个整数n(2≤n≤100)-数组a的长度。
每个测试用例的第二行包含n个整数a1,a2,…,an(1≤ai≤109)-数组a的元素。
输出 对于每个测试用例,如果不存在解决方案,则输出单个整数−1。
否则,在第一行中,分别输出两个整数lb和lc——数组波段c的长度。
在第二行中,输出lb整数b1,b2,…,bl——数组b的元素。
在第三行中,输出lc个整数c1,c2,…,cl——数组c的元素。
如果有多个解,输出其中任何一个。您可以以任何顺序输出数组中的元素。
思路
对于这一个数组,除了最大的数本身,其他的数都不会是最大的数的倍数,所以直接把最大的数放到数组b,其他的数放到数组a,需要进行特判,如果所有的数一样,也就是说最大的数否放到数组b之后数组a没有数字,此时不存在解输出“-1”
代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
int a[110]={0};
for(int i=0;i<n;++i)
{
scanf("%d",&a[i]);
}
int maxzhi=INT_MIN;
for(int i=0;i<n;++i)
{
maxzhi=max(maxzhi,a[i]);
}
vector<int>b,c;
for(int i=0;i<n;++i)
if(a[i]==maxzhi)c.push_back(a[i]);
else b.push_back(a[i]);
if(b.size()==0)printf("-1\n");
else
{
printf("%d %d\n",b.size(),c.size());
for(int i=0;i<b.size();++i)
printf("%d ",b[i]);
printf("\n");
for(int i=0;i<c.size();++i)
printf("%d ",c[i]);
printf("\n");
}
}
return 0;
}
B. Olya and Game with Arrays
题目大意
给你若干的数组,每一个数组里面至少会有两个数,现在对每一个数组都进行一次操作或者是不操作,在数组里选择一个数移动到其他的数组里面,最后每一个数组取最小值相加,求和的最大值
翻译:
阿尔乔姆向女孩奥利娅建议玩一个游戏。存在一个包含n个数组的列表,其中第i个数组包含mi≥2个正整数ai1, ai2,…,ai.mi。
Olya最多可以将一个整数(可能为0)从一个数组移动到另一个数组。请注意,整数只能从一个数组中移动一次,但整数可以多次添加到一个数组中,并且所有移动都是同时完成的。
数组列表的美妙之处在于求和∑ni=1minmij=1ai,j。换句话说,对于每个数组,我们找到其中的最小值,然后将这些值相加。
游戏的目标是最大化数组列表的美感。帮助奥利亚赢得这个具有挑战性的游戏!
输入 每个测试由多个测试用例组成。第一行包含一个整数t(1≤t≤25000)——测试用例的数量。下面是测试用例的描述。
每个测试用例的第一行包含一个整数n(1≤n≤25000)——列表中的数组数。
后面是数组的描述。每个数组描述由两行组成。
第一行包含一个整数mi(2≤mi≤50000)——第i个数组中的元素数。
下一行包含mi个整数ai,1,ai,2,…,ai,mi(1≤ai,j≤109)-第i个数组的元素。
可以保证所有测试用例的mi之和不超过50000。
输出 对于每个测试用例,输出包含单个整数的单行—这是Olya可以实现的数组列表的最大美感。
思路
每一个数组都可以选择移动或者是不移动,所以这个数组中最后能参与最后的最小值相加的数字只有可能是最小值或者是次小值(也就是第二小的数)要想把最后的值尽量变大,我们就优先把所有的最小值拿出来,放到一个数组里面,尽可能的使得每一个数组的次小值参与求和运算,最后最小值们都放到一个数组里面,我们找一个次小值里面最小的一个数组,放下所有的最小值即可。
代码
#include<iostream>
#include<bits/stdc++.h>
#include<vector>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
long long sum=0;
int zongminzhi1=INT_MAX;
int zongminzhi2=INT_MAX;
for(int i=0;i<n;++i)
{
int minzhi1=INT_MAX,minzhi2=INT_MAX;
int k;
scanf("%d",&k);
for(int j=0;j<k;++j)
{
int shuru;
scanf("%d",&shuru);
if(shuru<=minzhi1)
{
minzhi2=minzhi1;
minzhi1=shuru;
}
else if(shuru<=minzhi2)
{
minzhi2=shuru;
}
}
zongminzhi1=min(minzhi1,zongminzhi1);
zongminzhi2=min(minzhi2,zongminzhi2);
sum+=minzhi2;
}
printf("%lld\n",sum+zongminzhi1-zongminzhi2);
}
return 0;
}
C. Another Permutation Problem
题目大意
给你一个数n,在n的全排列中找到一个能够使得(∑ni=1=p i ⋅i)−(maxnj=1p j ⋅j)的值最大。
翻译:
安德烈刚刚开始出现问题,这对他来说很困难。这就是为什么他提出了一个关于排列的奇怪问题,并让你去解决它。你能做到吗?
让我们把长度为n的排列的代价称为表达式的值:
(∑ni=1=p i ⋅i)−(maxnj=1p j ⋅j)。找出长度为n的所有排列的最大代价。
长度为n的排列是由n个不同的整数以任意顺序从1到n组成的数组。例如,[2,3,1,5,4]是一个排列,但[1,2,2]不是一个排列(2在数组中出现两次),[1,3,4]也不是一个排列(n=3,但数组中有4)。
输入 每个测试由多个测试用例组成。第一行包含一个整数t(1≤t≤30)——测试用例的数量。下面是测试用例的描述。
每个测试用例的唯一一行包含一个整数n(2≤n≤250)——排列的长度。
可以保证所有测试用例的总和不超过500。
输出 对于每个测试用例,输出一个整数——长度为n的所有排列中的最大代价。
思路
通过打表发现所有的最大值都是发生在前面部分正序,后面一部分倒序的排序方法,比如说
n=2时,最大:2 1
n=3时,最大:1 3 2
n=4时,最大:1 2 4 3
n=5时,最大:1 2 5 4 3
n=6时,最大:1 2 3 6 5 4
n=7时,最大:1 2 3 4 7 6 5
n=8时,最大:1 2 3 4 8 7 6 5
…
以下是打板的代码:
#include<iostream>
#include<bits/stdc++.h>
#include<vector>
using namespace std;
int main()
{
int t=10;
for(int k=1;k<t;++k)
{
int maxzhi0=0;
{
cout<<"n=="<<k<<endl;
int a[200]{0};
int n=k;
for(int i=1;i<=n;++i)
{
a[i]=i;
}
int b[200]{0};
do
{
long long sum=0;
int maxzhi=INT_MIN;
for(int i=1;i<=n;++i)
{
sum+=a[i]*i;
maxzhi=max(maxzhi,a[i]*i);
}
if(maxzhi0<sum-maxzhi)
{
maxzhi0=sum-maxzhi;
for(int i=0;i<200;++i)
b[i]=a[i];
}
}while(next_permutation(a+1, a+n+1));
cout<<"max="<<maxzhi0<<endl;
for(int i=1;i<=n;++i)
cout<<b[i]<<' ';cout<<endl;
printf("***********\n");
}
}
return 0;
}
找到大致的规律之后只需要一个O(n)的枚举就好了,因为不知道最后的目标值大概是需要倒转多少个数字,直接暴力枚举
代码
#include<iostream>
#include<bits/stdc++.h>
#include<vector>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
scanf("%d",&n);
long long ans=0;
long long zong=0;
for(int i=1;i<=n;++i)
{
int maxzhi=0;
ans=0;
for(int j=1;j<=n-i;++j)
{
ans+=j*j;
maxzhi=max(maxzhi,j*j);
}
for(int j=n;j>=n-i+1;--j)
{
ans+=j*(n-i+1+(n-j));
maxzhi=max(maxzhi,j*(n-i+1+(n-j)));
}
ans-=maxzhi;
zong=max(ans,zong);
}
cout<<zong<<endl;
}
return 0;
}