CF961

A

先往从左下角到右上角的对角线进行填充,再不断地从两边填充。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=3e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
int main()
{
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
void solve()
{
int n,k; cin>>n>>k;
int ans=0;
if(k==0)
{
cout<<0<<"\n";
return;
}
for(int i=2*n+1;i>=1;i--)
{
if(i==2*n+1)
{
k-=n;
ans++;
}
else
{
k-=(i-1)/2;
ans++;
}
if(k<=0)
{
break;
}
}
cout<<ans<<"\n";
}

B1

直接进行统计模拟,需要注意的是:可能存在可以补充的情况。

如果先全取\(x\),再部分取\(x+1\),在总和小于\(m\)的情况下,可以少取\(x\),多取\(x+1\)

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=2e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}

void solve()
{
ll n,m; cin>>n>>m;
vector<ll> a(n);
map<ll,ll> mp;
for(int i=0;i<n;i++)
{
cin>>a[i];
mp[a[i]]++;
}
ll ans=0;
for(auto [x,y]: mp)
{
ll cnt_1=min(y,m/x); //尽可能多去x
ll tot=cnt_1*x;
if(mp.count(x+1))
{
ll num=mp[x+1];
ll cnt_2=min(num,(m-tot)/(x+1)); //尽可能多取x+1
tot+=cnt_2*(x+1);
num-=cnt_2; //计算剩余的x+1
ll add=min(num,cnt_1); //可能把x全替换,也可能只能替换一部分,最多就是剩余的x+1的数量
tot=min(tot+add,m); //需要小于m
}
ans=max(ans,tot); //更新最大值
}
cout<<ans<<"\n";
}

B2

思路跟上面一样。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=2e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}

void solve()
{
ll n,m; cin>>n>>m;
vector<ll> a(n);
map<ll,ll> mp;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
for(int i=0;i<n;i++)
{
int x; cin>>x;
mp[a[i]]=x;
}
ll ans=0;
for(auto [x,y]: mp)
{
ll cnt_1=min(y,m/x);
ll tot=cnt_1*x;
if(mp.count(x+1))
{
ll num=mp[x+1];
ll cnt_2=min(num,(m-tot)/(x+1));
tot+=cnt_2*(x+1);
num-=cnt_2;
ll add=min(num,cnt_1);
tot=min(tot+add,m);
}
ans=max(ans,tot);
}
cout<<ans<<"\n";
}

C

这题如果直接暴力模拟肯定会溢出,所以不行。

如果多写几个\(a_{i-1}\)\(a_i\)可以发现:如果两者都进行\(k\)次平方,让\(a_i>a_{i-1}\)的次数和原来是一样的。

使用\(b_i\)表示\(a_i\)需要的操作次数。

如果\(a_i<a_{i-1}\),模拟计算需要的次数\(cnt\),并且\(b_i=b_{i-1}+cnt\)

否则,对\(a_{i-1}\)进行计算(对\(a_i\)进行开方的操作次数\(cnt\)),\(b_i=max(0,b_{i-1}-cnt)\)。(这么搞是可以模拟计算出\(a_i\)需要的操作次数,如果\(cnt>b_{i-1}\),说明原来就比他大,根本不需要进行操作)。

麻烦的是一些细节,不好调。

#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
const int MAXN=2e5+10;
const int mod=998244353;
using namespace std;
using ll=long long;
void solve();
ll qpower();
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin>>t;
while(t--)
{
solve();
}
}
ll qpower(ll a,ll p)
{
ll ans=1;
while(p)
{
if(p&1) ans=ans*a;
a*=a;
p>>=1;
}
return ans;
}
void solve()
{
int n; cin>>n;
vector<ll> a(n);
vector<ll> b(n);
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int ans=0;
for(int i=1;i<n;i++)
{
if(a[i]==1 && a[i-1]>a[i])
{
cout<<-1<<"\n";
return;
}
else
{
if(a[i]<a[i-1])
{
int cnt=0;
ll t1=a[i-1],t2=a[i];
while(t1>t2)
{
t2*=t2;
cnt++;
}
b[i]=b[i-1]+cnt;
}
else
{
int cnt=0;
ll t1=a[i-1],t2=a[i];
if(t1==1) cnt=0;
else
{
while(t1<=t2)
{
t1*=t1;
cnt++;
}
cnt--;
}
b[i]=max(0ll,b[i-1]-cnt);
}
}
}
for(auto &t: b)
{
//cout<<t<<" ";
ans+=t;
}
//cout<<"\n";
cout<<ans<<"\n";
}