题意:给定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 "); 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*k); for(i=1; i<=n; i++) for(j=1; j<=k; j++)printf("%d ",c[j]); printf(" "); } 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 ",ans+1,l); } return 0; }