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);
 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";
 }
 
 | 
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)
 {
 
 ans+=t;
 }
 
 cout<<ans<<"\n";
 }
 
 
 |