A. Dense Array
题目大意:
给定一个数组,插入任意数字,要使数组的所有相邻两项满足,
那么最多需要进行多少次插入操作?
解析:贪心算法
#include<bits/stdc++.h>
using namespace std;
int a[100];
int main(){
int t;
cin>>t;
while(t--){
int n;
scanf("%d",&n);
for( int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
long long ans=0;
for( int i=2;i<=n;i++){
int small=min(a[i],a[i-1]);
int big=max(a[i],a[i-1]);
while(small*2<big){
small*=2;
ans++;
}
}
printf("%lld\n",ans);
}
}
B. Balanced Remainders
题目大意:
给定一个数组,将数组中的所有元素模3,要使数组其余1,余2,余0的个数相等,最少进行几次加一操作?
解析:模拟,余0的数加一就是余1的数,以此类推
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int c0=0,c1=0,c2=0,temp;
for( int i=1;i<=n;i++){
scanf("%d",&temp);
if(temp%3==0) c0++;
else if(temp%3==1) c1++;
else if(temp%3==2) c2++;
}
long long ans=0;
if(c0>n/3){
c1+=c0-n/3;
ans+=c0-n/3;
c0=n/3;
if(c1>n/3){
ans+=c1-n/3;
}
else{
if(c1<n/3){
ans+=2*(n/3-c1);
}
}
}
else if(c0<n/3){
if(c1>n/3){
ans+=c1-n/3;
c2+=ans;
ans+=n/3-c0;
}
else if(c1<n/3){
ans+=2*n/3-2*c1+(n/3-c0);
}
else ans+=n/3-c0;
}
else if(c0==n/3){
if(c1>c2) ans=n/3-c2;
else ans=2*(n/3-c1);
}
printf("%lld\n",ans);
}
}
C. Sum of Cubes
题目大意:
给定x,判断x是否满足a3+b3==x(a,b>1)
注:x的最大值是1e12
解析:判断一个数x是否满足条件,如果使用暴力枚举,每个数需要n2的时间复杂度。进行优化,可以先将所有的立方数算出,共有1e4个,首先枚举a3,再用二分查找检验
x-a^3是否存在。可以使用STL set。
#include<bits/stdc++.h>
using namespace std;
set<long long >cube;
int main(){
cube.clear();
for(long long int i=1;i*i*i<=1e12;i++){
cube.insert(i*i*i);
}
int t;
cin>>t;
while(t--){
long long x;
cin>>x;
int flag=1;
for(long long int i=1;i*i*i<=x;i++){
if(cube.find(x-i*i*i)!=cube.end()){
//check x-i^3 is in the set
flag=0;
break;
}
}
if(flag==0) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
D. Permutation Transformation
题目大意:给出一组二叉树的节点,大的为父节点,小的为子结点,父节点左侧的是左子树,父节点右侧的是右子树,按顺序输出每个节点的层数(父节点在第0层)。
解析:二叉树的递归遍历
#include<bits/stdc++.h>
using namespace std;
int a[110];
int ans[110];
int findmax(int l,int r){
int maxx=0,temp;
for(int i=l;i<=r;i++){
if(a[i]>maxx){
maxx=a[i];
temp=i;
}
}
return temp;
}
void check(int l,int r,int floor){
if(l>r) return ;
int pos = findmax(l,r);
ans[pos]=floor;
check(l,pos-1,floor+1);
check(pos+1,r,floor+1);
return ;
}
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for( int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
check(1,n,0);
for(int i=1;i<=n;i++){
printf("%d ",ans[i]);
}
cout<<endl;
}
}
E. Accidental Victory
题目大意:
有n个人,每人有数个硬币,他们之间要进行n-1场比赛。对于每一场比赛,硬币多的人会拿走硬币少的人的所有硬币,最后有硬币的人称为winner。请问最后有几个人有可能称为winner?输出他们的序号。
解析:前缀和
#include<bits/stdc++.h>
using namespace std;
struct num{
int pos,x;
};
num a[200100];
long long int f[200100];//前缀和数组,注意开long long
int ans[200100];
int cmp( num a,num b){
return a.x<b.x;
}
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
memset( ans,0,sizeof(ans));
for( int i=1;i<=n;i++){
scanf("%d",&a[i].x);
a[i].pos=i;
}
sort(a+1,a+1+n,cmp);
for( int i=1;i<=n;i++){
f[i]=a[i].x+f[i-1];
}
ans[a[n].pos]=1;
int count=1;
for( int i=n-1;i>=1;i--){
if(f[i]>=a[i+1].x)
{
ans[a[i].pos]=1;
count++;
}
else break;
}
cout<<count<<endl;
for( int i=1;i<=n;i++){
if(ans[i]) printf("%d ",i);
}
cout<<endl;
}
}
F. Equalize the Array
题目大意:
给定一个数组,数组中有n个数,现在让数组变成beautiful,意思是数组中的每个数只出现1次或者n次
解析:离散化+疑似dp
#include<bits/stdc++.h>
using namespace std;
int a[200100];
int b[200100];
int cmp(int a,int b){
return a>b;
}
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
int temp=a[1],count=0,j=1;
a[n+1]=-1;//处理边界点
for( int i=1;i<=n+1;i++){//离散化处理
if(temp==a[i]) count++;
else{
b[j]=count;
j++;
count=1;
temp=a[i];
}
}
sort(b+1,b+j,cmp);
int ans=1e9,sum=0;
for( int i=1;i<j;i++){
sum+=b[i];
ans=min(sum-b[i]*i,ans+b[i]);
}
cout<<ans<<endl;
}
}
G. Old Floppy Drive
题目大意:不会写了,网上的答案。。。。。。
模拟,数学
题意为给出一列数,指针起始时位于下标1的位置,每隔一秒指针会向后移动一格并取走相应位置的数n往后走为1,要求求出对于给定的数x,指针至少走多久时间能够取得总和大于x的数或者永远取不到。
解析:首先考虑取不到的情况,即每次循环完一遍n个数,取得数的总和sum不增,并且在一个周期的过程中所取得数总和sum的最大值小于x。对a数组求一遍前缀和,条件即为a[n]<=0&&max(a[i])<x,i∈[1,n]。直接输出-1即可。
其余情况都可以取到x,先对数组a求一遍前缀和,再求出取得的数总和sum达到x-max(a[i])时所需的循环次数,最后一次遍历求出前缀和数列中第一个比x-sum大的数所在位置pos,这个地方我用线段树查询,直接遍历会超时,答案即为前面循环所耗费的次数加上pos,由于起始位置位于1,所以最后结果要再减一。