传送门
A. Sequence with Digits
题意
给定(a,k), 每次使得(a)进行如下计算:
求(k)次计算后的值
数据范围
(1 leq a_{1} leq 10^{18}, 1 leq K leq 10^{16})
题解
在一定次数的计算后,出现0就不会改变了,直接break
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
int _;
int main(){
for(scanf("%d",&_);_;_--){
ll a,k;
cin>>a>>k;
bool flag=1;
k--;
while(k-- && flag){
ll t=a;
ll mn=1e18,mx=0;
while(t){
ll x=t%10;
//if(x==0) {flag=0;break;}
t/=10;
mn=min(mn,x);
mx=max(mx,x);
}
if(mn==0 || mx==0) break;
a+=mn*mx;
}
cout<<a<<endl;
}
}
B. Young Explorers
题意
给定(N)个人,每个人有一个经验值(e),每个人只能存在于人数大于等于他经验值得队,求出可以分配的最大的队伍
数据范围
(1 leq N leq 2 cdot 10^{5})
(1 leq e_{i} leq N)
题解
从小到大贪心,贪心的策略是不多分配,可以分配一个群组就分配恰好的数量,
维护一个当前的人数即可,
存在一个单调性,即当前人之前剩下的人数一定不会大于当前人的经验值
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
int _;
const int N=2e5+10;
int e[N];
int main(){
for(scanf("%d",&_);_;_--){
unordered_map<int,int>p;
set<int>s;
int n;
scanf("%d",&n);
rep(i,0,n) {int x;scanf("%d",&x); p[x]++; s.insert(x);}
int now=0;
int ans=0;
for(auto it:s){
now+=p[it];
if(it <= now) {
ans+=now/it;
now-=(now/it * it);
}
}
printf("%d
",ans);
}
}
C. Count Triangles
题意
给定(A,B,C,D)求一个三角形的三边(x,y,z),满足(A leq xleq B leq yleq Cleq z leq D),求在合法范围内能构成多少种三角形
数据范围
(1 leq A leq x leq Bleq y leq C leq zleq D leq10^{5})
题解
用较小的两边之和(sum)大于第三边判断三角形是否合法,枚举小的两边和, 求出在合法的范围内第三条边的个数为(min(D , sum-1) - C +1),
再求出两条边的和为(i)的个数,
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
int main(){
ll a,b,c,d;
cin>>a>>b>>c>>d;
ll ans=0;
for(ll i=a+b;i<=b+c;i++){
ll z=min(d,i-1)-c+1,t=min(i-b,b)-max(i-c,a)+1;
if(z<0 || t<0) continue;
ans+=z * t;
}
cout<<ans<<endl;
}
D. Game With Array
题意
构造一个数组长度为(N),和为(S) 的数组,一个(K), 问是否能构造出使得所有的子序列和不等于(K)和(S-K)
数据范围
(1leq Nleq Sleq 10^{6})
(0 leq K leq S)
题解
前(n-1)全填(2),剩下的如果(leq 1)则无法构造出,否则只要选择(K=1)即可
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
int main(){
int n,s;
cin>>n>>s;
int s_=s-(n-1)*2;
if(s_<=1){puts("NO");return 0;}
vi ans;
rep(i,0,n-1) ans.pb(2);
ans.pb(s_);
puts("YES");
for(auto it: ans)
cout<<it<<' ';
puts("");
cout<<"1"<<endl;
}
E. Restorer Distance
题意
给定(N)堆盘的高度(h_{i}),三个操作,
- 添加一个到一个的最上面代价(A)
- 移除一个最上面的代价(B)
- 将一个的最上面的移动到另一个上代价(M)
求出让所有的堆高度相同的最小代价
数据范围
(1leq N leq 10^{5})
(0 leq h_{i} leq 10^{9})
$ 0 leq A, R, M leq 10^{4}$
题解
首先可以将(M)换成(min(M,A+B)),可以看出来代价关于高度h是一个单谷函数,因此三分求最小值
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define fi first
#define se second
#define ll long long
#define pb push_back
typedef pair<long long,long long> pll;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<long long> vll;
typedef double db;
const ll mod=1e9+7;
ll powmod(ll a,ll b,ll p){ll res=1;a%=p;while(b){if(b&1) res=res*a%p;a=a*a%p;b>>=1;}return res;}
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
const int N=1e5+10;
ll h[N];
ll n,a,r,m;
ll cal(ll x){
ll add=0,del=0;
for(int i=0;i<n;i++) {
if(h[i]>x) del+=h[i]-x;
if(h[i]<x) add+=x-h[i];
}
ll delta=abs(del-add),move=min(del,add);
ll res=0;
res+=move*m;
if(del>add) res+=delta*r;
if(add>del) res+=delta*a;
return res;
}
int main(){
cin>>n>>a>>r>>m;
m=min(m,a+r);
for(int i=0;i<n;i++) cin>>h[i];
ll l=0,r=1e9;
while(l<r){
ll lmid=(l*2+r)/3,rmid=(r*2+l+2)/3;
if(cal(lmid)<cal(rmid)) r=rmid-1;
else l=lmid+1;
}
cout<<cal(l)<<endl;
}