炼石 plan 10.5
A. 最棒的玩具销售员
nth_element
宣传片。
直接套路二分 \(t\) 去调整可以过题,注意带 \(\log\) 的无法通过要弄一点 \(O(n)\) 玩意儿。
然后写总结的时候发现这玩意儿怎么能过的题目,这哪里有二分的单调性了,但是仔细思考之后发现有三分的单调性 /fad
总和斜率 \(k\uparrow\),这部分的前缀和是凸包,然后 \(b\) 的影响不影响凸性。
#include<bits/stdc++.h>
#define int long long
#define ll __int128
#define up(i,l,r) for(register int i=l; i<=r; ++i)
#define dn(i,r,l) for(register int i=r; i>=l; --i)
using namespace std;
inline int read() {
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') flag=0; ch=getchar(); }
while(ch>='0'&&ch<='9') { X=(X<<1)+(X<<3)+ch-'0'; ch=getchar(); }
if(flag) return X;
return ~(X-1);
}
const int N=1000005;
int n, m, s, k[N], b[N];
ll a[N];
inline bool check(int x) {
up(i,1,n) a[i]=(ll)k[i]*x+b[i];
nth_element(a+1,a+n-m+1,a+1+n);
ll sum=0;
up(i,n-m+1,n) sum+=max((ll)0,a[i]);
return sum>=s;
}
signed main() {
freopen("merchant.in","r",stdin);
freopen("merchant.out","w",stdout);
n=read(), m=read(), s=read();
up(i,1,n) k[i]=read(), b[i]=read();
int l=0, r=1e18, Ans;
while(l<=r) {
int mid=(l+r)>>1;
if(check(mid)) Ans=mid, r=mid-1;
else l=mid+1;
}
cout << Ans;
return 0;
}
B. 只因数分解
爆搜之后发现只因数总量不多,支持预处理顺便排个序。
查询就贪心每次拿最大的,正确性不会说但是这种很难不过吧。
#include<bits/stdc++.h>
#define int long long
#define ll __int128
#define up(i,l,r) for(register int i=l; i<=r; ++i)
#define dn(i,r,l) for(register int i=r; i>=l; --i)
#define pb push_back
using namespace std;
const int N=21;
int t, n, m, cnt[N];
vector<int> F[N];
bool P(int x) {
up(i,2,x-1) if(x%i==0) return 0;
return 1;
}
void dfs(int t,int x,int mul) {
if(x>t) {
F[t].pb(mul);
return;
}
dfs(t,x+1,mul);
up(i,1,cnt[x]) {
mul*=x;
dfs(t,x+1,mul);
}
}
signed main() {
freopen("end.in","r",stdin);
freopen("end.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
up(t,1,20) {
up(i,2,t) cnt[i]=0;
up(i,2,t) if(P(i)) {
up(j,1,t) {
int tmp=j;
while(tmp%i==0) tmp/=i, ++cnt[i];
}
}
dfs(t,1,1);
sort(F[t].begin(),F[t].end());
}
cin >> t;
while(t--) {
cin >> n >> m;
vector<int> Ans;
while(m) {
int i=upper_bound(F[n].begin(),F[n].end(),m)-F[n].begin()-1;
m-=F[n][i], Ans.pb(F[n][i]);
}
cout << Ans.size() << '\n';
for(int x:Ans) cout << x << ' ';
cout << '\n';
}
return 0;
}
C. 西琳的魔法字符串
首先进行一个转化,(/)
的权值设置为 \(1/-1\),那么答案就是 \(count(')')+权值最大前缀\)。
大量手玩之后可以发现是要保留 \(不相交的 1个前缀 + k 段\),反悔贪心即可,要用线段树维护最大和区间和区间取反。