2020-05-18 — 习题训练一
题意:给定n个数,从1-n分别是2^1,2^2……2^n,然后把他们分成个数相同的2部分,问如何分才能使得a-b的绝对值最小
题解: 根据各个值可以发现2^n一定比前面的所有数字相加都大,就是2^n>2^n-1+2^n-2……2^1,所以把最大值给一边,然后从大到小把n/2的值给另外一边就行
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int t,n,sum1,sum2;
cin>>t;
while(t--){
cin>>n;
sum1=0;
sum2=pow(2,n);
for(int i=n/2;i<=n-1;i++){
sum1+=pow(2,i);
}
for(int i=1;i<n/2;i++){
sum2+=pow(2,i);
}
cout<<abs(sum1-sum2)<<endl;
}
return 0;
}
题意:给定n个数,要求他们按顺序k个数相加都要相等,可以在中间添数字,如果没有办法使他们相等则输出-1(a1,a2,a3,a4,如果k=2的话就是a1+a2=a2+a3=a3+a4=a4)
题解:找周期吧,设他们有多少个不同的数为k1,如果k1>k,那么无论怎么加数字都不能成功输出-1,否则可以输出n个周期(比如n=4 k=3,就可以1 2 3 1 2 3 1 2 3 1 2 3)
代码:
#include <cstdio>
#include <algorithm>
using namespace std;
int a[105],vis[105],c[105],cn;
int main() {
int t,i,b,n,k,cnt,j;
scanf("%d",&t);
while(t--) {
scanf("%d%d",&n,&k);
for(i=1; i<=100; i++)vis[i]=0;
for(i=1; i<=n; i++)scanf("%d",&a[i]),vis[a[i]]=1;
cnt=0;
for(i=1; i<=100; i++) if(vis[i])cnt++;
if(cnt>k) {
printf("-1\n");
continue;
}
if(cnt<k) for(i=1; i<=100; i++) if(!vis[i]) {
vis[i]=1,cnt++;
if(cnt==k)break;
}
cn=0;
for(i=1; i<=100; i++) if(vis[i])c[++cn]=i;
printf("%d\n",n*k);
for(i=1; i<=n; i++) for(j=1; j<=k; j++)printf("%d ",c[j]);
printf("\n");
}
return 0;
}
C - Road To Zero
题意:给你x和y,你有2个方法一个是他们每个都减1花费a元或者使其中一个减1花费b元,问怎样使得花费最低。
题解:就是找出花费最低的一个方法,当x和y都不是0时,可以通过第一种方法把其中最小的变为0,然后再加上剩下的值,或者全部使用第二个方法,比较他们2个哪个方案最小(如果第一种方法小于第二种时,不能一直使用第二种,因为其中一个数为0时不能再一起-1 - ,-)
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
int t;
ll x,y;
ll a,b;
ll sum1,sum2,sum3;
cin>>t;
while(t--){
cin>>x>>y;
cin>>a>>b;
// if(b<=a){
// sum1=max(x,y)*b;
// cout<<sum1<<endl;
// }
//else{一个数到0不能2个一起减
sum2=min(x,y)*b+(max(x,y)-min(x,y))*a;
sum3=(x+y)*a;
cout<<min(sum2,sum3)<<endl;
// }
}
return 0;
}
D - Binary Period
题意:跟第二题类似,只不过只能01串,然后添加数字使得他们有周期,最后的序列长度要小于等于2*s
题解:如果序列只有相同的数,那肯定本身就有周期了是1,如果不相同,就一直0101排列就好(比如010,s的长度是3那就可以输出一个长度6的序列要有周期,直接输出010101就可)
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int t,l,flag;
string a;
cin>>t;
while(t--){
flag=0;
cin>>a;
l=a.size();
for(int i=0;i<a.size()-1;i++){
if(a[i]!=a[i+1]){
flag=1;//有2个字符
break;
}
}
if(flag==0){
cout<<a<<endl;
}
else{
for(int i=0;i<l;i++){
cout<<"1"<<"0";
}
cout<<endl;
}
}
return 0;
}
E - Nastya and Rice
题意:
给你一个一袋米重量的范围和其中每一粒米的重量范围,问n个这些米是否在这个范围内
题解:
就是如果最大的重量*n<一袋米的重量或者最小的重量*n>一袋米的重量就不符合
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int t;
int n,a,b,c,d;
int flag;
cin>>t;
while(t--){
flag=0;
cin>>n>>a>>b>>c>>d;
if(n*(a-b)>c+d){
flag=1;
}
if(n*(a+b)<c-d){
flag=1;
}
if(flag==1){
cout<<"No"<<endl;
}
else{
cout<<"Yes"<<endl;
}
}
return 0;
}
F - Nastya and Door
题意:
给定一个序列,如果其中一个数大于左边且大于右边就能把他们分开(an>an-1&&an>an+1)然后再取一个k为从这个序列取k的长度,问哪一个取法能把他们分得最开
题解:
一开始看半天没看懂。。。然后其实可以用前缀和做,把i-1中有峰值记录下来,然后根据给定的长度算出a[i+k]-a[k],看哪边的峰值最多输出就好,题目有个坑,如果i和i+k是峰值,那a[i+k]-a[i]=0的,就是本身使不能算,后面一个值才能+1
代码:
#include<bits/stdc++.h>
using namespace std;
int f[200005];
int main()
{
int t;
scanf("%d",&t);
int n,k;
int fr1,fr2;
int fr3;
int ans;
int l=1;
while(t--)
{
memset(f,0,sizeof(f));
scanf("%d%d",&n,&k);
scanf("%d%d",&fr1,&fr2);
for(int i=3;i<=n;i++)
{
scanf("%d",&fr3);
if(fr2>fr1&&fr2>fr3) f[i]=f[i-1]+1;
else
{
f[i]=f[i-1];
}
fr1=fr2;
fr2=fr3;
}
ans=0;
l=1;
for(int i=k;i<=n;i++)
{
if(ans<f[i]-f[i-k+2])
{
ans=f[i]-f[i-k+2];
l=i-k+1;
}
}
printf("%d %d\n",ans+1,l);
}
return 0;
}

浙公网安备 33010602011771号