A.模拟:https://codeforces.com/contest/1995/problem/A
AC代码:
#include<bits/stdc++.h>
using namespace std;
int n,t,k;
int main(){
cin>>t;
while(t--){
cin>>n>>k;
int cnt=0;
if(k==0) cout<<0<<endl;
else if(k<=n) cout<<1<<endl;
else{
cnt++;
k-=n;
for(int i=n-1;i>=1;i--){
if(k<=0) break;
else if(k<=i){
cnt++;
k-=i;
}
else{
cnt+=2;
k-=2*i;
}
}
cout<<cnt<<endl;
}
}
}
B枚举:https://codeforces.com/contest/1995/problem/B1
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,t,m;
ll a[200010];
struct node{
ll x,ci;
}b[200010];
int cnt=1;
int main(){
cin>>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
ll ans=0;
//枚举两个
cnt=1;
int j=1;
for(int i=1;i<=n;i++){
if(a[i]==a[j]) continue;
b[cnt++]={a[j],i-j};
j=i;
}
b[cnt++]={a[j],n-j+1};
for(int i=1;i<cnt-1;i++){
ll x=b[i].x,k1=b[i].ci,y=b[i+1].x,k2=b[i+1].ci;
if(x>m) break;
if(y!=x+1) continue;
for(int j=0;j<=k1;j++){
ll fk=m-j*x;
if(fk==0) ans=m;
else if(fk<0) break;
else{
ll cc=fk/y;
if(cc<=k2) ans=max(ans,j*x+cc*y);
else ans=max(ans,j*x+k2*y);
}
}
}
for(int i=1;i<cnt;i++){
ll x=b[i].x,k1=b[i].ci;
if(x>m) break;
ll cc=m/x;
if(cc<=k1) ans=max(ans,cc*x);
else ans=max(ans,x*k1);
}
cout<<ans<<endl;
}
}
C数学,分类讨论:https://codeforces.com/contest/1995/problem/B2
把x,x+1当成同等地位可能反而会把问题复杂化,我们不妨以x为主,x+1作为x的补充:
首先,问题就是给你两个数:以及他们的个数
,如何凑出<=m的最大值。
假如不考虑的存在,答案就显然是
考虑带来的影响:一方面假如
,那么对于
来说就是使他的解变成了一个区间:
.
另一方面假如,那么就让
去填充
,剩下的就对用了的k1个进行优化,也就是:
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define x first
#define y second
ll t,n,m;
pair<ll,ll> a[200010];
ll ans=0;
int main(){
cin>>t;
while(t--){
ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i].first;
for(int i=1;i<=n;i++) cin>>a[i].second;
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
ans=max(ans,min(m/a[i].x,a[i].y)*a[i].x);
}
//枚举两个
for(int i=1;i<=n-1;i++){
if(a[i].x!=a[i+1].x-1) continue;
ll cnt1=m/a[i].x;
if(cnt1<=a[i].y){
if(cnt1!=0) ans=max(ans,min(cnt1*a[i].x+min(a[i+1].y,cnt1),m));
}
else{//需要用a[i+1]继续填充
ll cnt2=(m-a[i].x*a[i].y)/a[i+1].x;
if(cnt2<=a[i+1].y){
//if(cnt2==0) ans=max(ans,a[i])
ans=max(ans,min(m,a[i].x*a[i].y+a[i+1].x*cnt2+min(a[i+1].y-cnt2,a[i].y)));
}
else{
ans=max(ans,a[i].x*a[i].y+a[i+1].x*a[i+1].y);
}
}
}
cout<<ans<<endl;
}
}
D。数学:https://codeforces.com/contest/1995/problem/C
假如后面的数比前面的小就平方,一旦比他大就下一个,这个贪心是显然的,但是问题在如果真的老实平方化后面的数会非常大难以表示,于是我们进一步思考:
设前面的数是a,他要被平方k次,现在我们求他后面的b要平方几次:
通过不停的开方可以得到:
于是我们可以记录a的平方次数,然后枚举k1-k(在5的时候b就以经比a的数据范围大了)即可。
当然k1-k存在负数,我们把指数放到a头上对称来一次即可,具体见下面AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,a[200010];
ll b[200010];
ll pow1(ll a,ll b){
ll res=0;
while(b){
if(b&1) res+=a;
b>>=1;
a=a*a;
}
return res;
}
int main(){
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
ll cnt=0;
for(int i=2;i<=n;i++){
if(a[i-1]!=1&&a[i]==1){
cnt=-1;
break;
}
for(int k=0;k<=5;k++){
ll fk=2;
ll mi=pow(fk,k);
if(pow(a[i],mi)>=a[i-1]&&k!=0){
b[i]=b[i-1]+k;
cnt+=b[i];
break;
}
else if(pow(a[i],mi)>=a[i-1]&&k==0){
for(int j=5;j>=0;j--){
ll ck=pow(fk,j);
if(pow(a[i-1],ck)<=a[i]){
ll kk=0;
b[i]=max(b[i-1]-j,kk);
cnt+=b[i];
break;
}
}
break;
}
}
}
cout<<cnt<<endl;
}
}