good problem-2
1.E1. Cats on the Upgrade (easy version)
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<ll,int>
using namespace std;
const int maxn=5e6+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
ll n,q,p[maxn],pre[maxn];
int main(){
n=read();q=read();
char ch[maxn];cin>>ch;
stack<int>qq;
for(int i=1;i<=n;i++){
if(ch[i-1]=='(')qq.push(i);
else if(!qq.empty())p[i]=p[qq.top()-1]+1,qq.pop();
pre[i]=pre[i-1]+p[i];
}
for(int i=1;i<=q;i++){
int t=read(),l=read(),r=read();
printf("%lld\n",pre[r]-pre[l-1]-(p[r]-p[l-1])*p[l-1]);
}
return 0;
}
2.Division
首先把数组中的\(a_i\)变为\(log_2(a_i)\)(也就是除2变为1的次数)
这样这道题就转化为每次操作将长度大于k的区间的数减一,求最小操作次数使得数组全为0
对于这种区间加减的题可以考虑差分思想,把a数组转为差分数组,这样就是求差分数组全为0的最小操作次数
每次区间[l,r]减一可以看作\(a_l-1,a_{r+1}+1\)
那么从前往后扫,遇到一个小于0的\(a_r\),从前面最远\(大于0的a_l (且 k\leq r-l)\)来抵消\(a_r\),这样就实现了[l,r-1]的区间减一,若\(a_l\)不足以抵消,那么l++重复上述过程,如果\(k> r-l\)那么就无法成立,输出-1
这样操作数最小,因为差分之后,每个+都需要一个-来消除,所以操作数是固定的。当你做多余操作比如在该-的地方进行+,才会导致操作数变多
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=1e5+101;
const int MOD=1e9+7;
const int inf=2147483647;
const double pi=acos(-1);
ll read(){
ll x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int t,n,k,a[maxn];
int main(){
t=read();
while(t--){
n=read();k=read();a[n+1]=a[0]=0;
for(int i=1;i<=n;i++){
ll x=read();a[i]=0;
while(x>1)a[i]++,x>>=1;
}
for(int i=n+1;i>0;i--)a[i]-=a[i-1];
int l=1;bool fa=true;
vector<pa>ans;ans.clear();
for(int i=2;i<=n+1;i++){
if(a[i]<0 && i-l<k){fa=false;break;}
while(a[i]<0){
if(i-l<k){fa=false;break;}
if(-a[i]>=a[l]){
a[i]+=a[l++];
while(a[l-1]){
ans.push_back(make_pair(l-1,i-1));
a[l-1]--;
}
}
else {
a[l]=a[l]+a[i];a[i]=-a[i];
while(a[i]){
ans.push_back(make_pair(l,i-1));
a[i]--;
}
}
}
if(!fa)break;
}
for(int i=1;i<=n+1;i++){
if(a[i]){fa=false;break;}
}
if(!fa)printf("-1\n");
else {
printf("%lu\n",ans.size());
for(auto i: ans)printf("%d %d\n",i.first,i.second);
}
}
return 0;
}
3.gcd
首先题目可以转化为
\(\sum_i \prod_{j=1}^n (\lfloor \frac{r_j}{i} \rfloor -\lfloor \frac{l_j-1}{i} \rfloor)\)
括号里可以考虑整除分块,\((\lfloor \frac{r_j}{i} \rfloor -\lfloor \frac{l_j-1}{i} \rfloor)\)的取值在\(i\in [l,r]\)内是相同的,并且取值的个数是\(\sqrt n\)量级的,
那么可以对于每个j,对于一个取值相同的区间乘以当前的取值(每个j都在ans的数组进行乘操作,这样\(\sum_{i=1}ans_i就是答案\))
首先能够想到线段树进行区间乘法,但是带个log
考虑差分思想,区间[l,r]乘v等同于\(ans_l*v,ans_{r+1}*\frac{1}{v}\)
但是乘以0要单独考虑,用c数组记录乘以0的区间,也同样用差分
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=5e5+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
ll power(ll x,ll y){
ll ans=1;
while(y){
if(y&1)ans=ans*x%MOD;
y>>=1;x=x*x%MOD;
}
return (ans%MOD+MOD)%MOD;
}
int n,book[maxn],c[maxn];
ll ans[maxn],inv[maxn];
struct wzq{int l,r;}a[maxn];
int main(){
n=read();int maxx=0;
for(int i=1;i<=n;i++){
a[i].l=read();a[i].r=read();
maxx=max(maxx,a[i].r);
}
inv[1]=1;
for(int i=2;i<=300000;i++)inv[i]=(ll)(MOD-MOD/i)*inv[MOD%i]%MOD;
for(int i=0;i<=maxx;i++)ans[i]=1;
for(int i=1;i<=n;i++){
a[i].l--;c[a[i].r+1]++;
for(int l=1,r,r1,r2;l<=a[i].r;l=r+1){
int x=a[i].r/l,y=a[i].l/l;
r1=a[i].r/x;
if(y)r2=a[i].l/y;
else r2=a[i].r;
r=min(r1,r2);
ll now=(x-y)%MOD;
if(!now)c[l]++,c[r+1]--;
else {
ans[l]=ans[l]*now%MOD;
ans[r+1]=ans[r+1]*inv[now]%MOD;
}
}
}
ll sum=0;
for(int i=1;i<=maxx;i++){
ans[i]=ans[i]*ans[i-1]%MOD;c[i]+=c[i-1];
if(!c[i])(sum+=ans[i])%=MOD;
}
printf("%lld",(sum%MOD+MOD)%MOD);
return 0;
}
另一道整出分块题GCD
题解:
如果要判断gcd为a是否能够被选出,那么就需要判断[l,r]能否选出至少k个a的倍数
即r/a-(l-1)/a>=k
我们发现r/a的值可以用整除分块算出,(l-1)/a的值也可以整除分块算出。将算出的这些值用双
指针进行组合,即可得到r/a-(l-1)/a>=k所有可能的取值。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define pa pair<ll,int>
using namespace std;
const int maxn=3e5+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
const double eps=1e-12;
ll read(){
ll x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int main(){
ll l=read()-1,r=read(),k=read(),ans=0;
for(ll i=1,j;i<=r;i=j+1){
j=min(r/(r/i),i<=l?l/(l/i):r/(r/i));
if(r/i-l/i>=k)ans+=j-i+1;
}
printf("%lld\n",ans);
return 0;
}
4.E - Average and Median
平均数:二分平均数mid,把序列全部减去mid,按题目要求用dp求最大值,大于0就说明可以
中位数:二分中位数mid,把序列大于mid的设为1,小于mid的设为-1,按题目要求用dp求最大值,大于0就说明可以
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=5e5+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
ll read(){
ll x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,a[maxn],b[maxn],c[maxn];
int main(){
n=read();
for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i];
double l=0,r=inf,ans;
//l从0开始不能从1开始,因为若序列都为1则无法得到正确结果
while(r-l>1E-4){
vector<double>dp(n+1);
double mid=(l+r)/2.0;
for(int i=1;i<=n;i++){
if(i==1){dp[i]=a[i]-mid;continue;}
if(i==2){dp[i]=max(0.0,dp[1])+a[i]-mid;continue;}
dp[i]=max(dp[i-1],dp[i-2])+a[i]-mid;
}
if(max(dp[n],dp[n-1])>0)ans=mid,l=mid;
else r=mid;
}
printf("%.4lf\n",ans);
ans=0;sort(b+1,b+n+1);int tot=0;
for(int i=1;i<=n;i++){
if(b[i]!=b[i-1])b[++tot]=b[i];
}
int l1=1,r1=tot;
while(r1>=l1){
int mid=(l1+r1)>>1,mm=b[mid];
vector<int>dp(n+1);
for(int i=1;i<=n;i++){
int now=((a[i]-mm)<0?-1:1);
if(i==1){dp[i]=now;continue;}
if(i==2){dp[i]=max(0,dp[1])+now;continue;}
dp[i]=max(dp[i-1],dp[i-2])+now;
}
if(max(dp[n],dp[n-1])>0)ans=mm,l1=mid+1;
else r1=mid-1;
}
printf("%d\n",(int)(ans));
return 0;
}
5.F - |LIS| = 3
考虑nlogn的求最大上升子序列的做法
设\(dp_{i,x1,x2,x3}\)为到第i位置,最长上升序列长度为1/2/3的最后一位的最小值为x1/x2/x3
到第i+1位通过枚举当前为的可能的数,来进行转移
注意最长上升长度不能超过3
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,m;
ll dp[1001][12][12][12];
int main(){
n=read();m=read();
dp[0][m+1][m+1][m+1]=1;
//m+1就记为当前没有该长度的最长上升子序列
for(int i=0;i<n;i++)for(int x1=1;x1<=m+1;x1++)for(int x2=1;x2<=m+1;x2++)for(int x3=1;x3<=m+1;x3++){
if(!dp[i][x1][x2][x3])continue;
for(int j=1;j<=m;j++){
if(j<=x1)(dp[i+1][j][x2][x3]+=dp[i][x1][x2][x3])%=MOD;
else if(j<=x2)(dp[i+1][x1][j][x3]+=dp[i][x1][x2][x3])%=MOD;
else if(j<=x3)(dp[i+1][x1][x2][j]+=dp[i][x1][x2][x3])%=MOD;
}
}
ll ans=0;
for(int x1=1;x1<=m;x1++)for(int x2=1;x2<=m;x2++)for(int x3=1;x3<=m;x3++)(ans+=dp[n][x1][x2][x3])%=MOD;
printf("%lld",ans);
return 0;
}
6.F - Two Exams
因为题目中的每个citizen有2个参数,不妨先降维,以第一维从大到小排序获得第二维的数组
题目要求未选中的citizens中不能有比选中的更优的可能
所以设\(dp_{i,j,k}\)为前i个(排完序的第二维数组中)数中选j个,其中剩下i-j个citizens中的最小值
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,K;
ll dp[302][302][302];
struct wzq{int fir,sec;}a[302];
bool cmp(wzq i,wzq j){return i.fir<j.fir;}
int main(){
n=read();K=read();
for(int i=1;i<=n;i++)a[i].fir=read();
for(int i=1;i<=n;i++)a[i].sec=read();
sort(a+1,a+n+1,cmp);dp[0][0][n+1]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=min(i,K);j++){
for(int k=1;k<=n+1;k++){
if(!dp[i-1][j][k])continue;
(dp[i][j][min(a[i].sec,k)]+=dp[i-1][j][k])%=MOD; //不选
if(k>a[i].sec)(dp[i][j+1][k]+=dp[i-1][j][k])%=MOD; //选
}
}
}
ll ans=0;
for(int k=1;k<=n;k++)(ans+=dp[n][K][k])%=MOD;
if(K==n)ans=dp[n][K][n+1]; //如果K==n,全都选
printf("%lld",(ans%MOD+MOD)%MOD);
return 0;
}
7.[SDOI2009]HH的项链
显然这种查询区间种类的操作是不能用普通线段树的区间操作
考虑每个项链的贡献
因为是离线操作,可以先固定r,那么[l,r]区间的贡献就是从后往前不同项链的个数
那么我们可以对于每个位置i,记录pre[i]为上一个颜色的位置,随着r的推移,add(r,1),add(pre[r],-1)
这样就能进行区间查询
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=1e6+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,m,sum[maxn],pre[maxn],book[maxn];
struct wzq{
int l,r,id;
}q[maxn];
bool cmp(wzq i,wzq j){
return i.r<j.r;
}
bool cmp1(wzq i,wzq j){
return i.id<j.id;
}
int lowbit(int x){return x&(-x);}
void add(int l,int val){
if(!l)return ;
for(int i=l;i<=n;i+=lowbit(i))sum[i]+=val;
}
int query(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))ans+=sum[i];
return ans;
}
int main(){
n=read();
for(int i=1;i<=n;i++){
int x=read();
pre[i]=book[x];
book[x]=i;
}
m=read();
for(int i=1;i<=m;i++){q[i].l=read();q[i].r=read();q[i].id=i;}
sort(q+1,q+m+1,cmp);
int r=0;
for(int i=1;i<=m;i++){
while(r<q[i].r){
r++;
add(r,1);
add(pre[r],-1);
}
q[i].l=query(q[i].r)-query(q[i].l-1);
}
sort(q+1,q+m+1,cmp1);
for(int i=1;i<=m;i++)printf("%d\n",q[i].l);
return 0;
}
[HEOI2012]采花
这道题也是同理,只是倒着做
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,c,m,sum[maxn],bk[maxn],book[maxn];
struct wzq{
int l,r,id;
}q[maxn];
bool cmp(wzq i,wzq j){
return i.l>j.l;
}
bool cmp1(wzq i,wzq j){
return i.id<j.id;
}
int lowbit(int x){return x&(-x);}
void add(int l,int val){
if(!l)return ;
for(int i=l;i<=n;i+=lowbit(i))sum[i]+=val;
}
int query(int x){
int ans=0;
for(int i=x;i;i-=lowbit(i))ans+=sum[i];
return ans;
}
int a[maxn];
int main(){
n=read();c=read();m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=n;i;i--){
bk[i]=book[a[i]];
book[a[i]]=i;
}
for(int i=1;i<=m;i++){q[i].l=read();q[i].r=read();q[i].id=i;}
sort(q+1,q+m+1,cmp);
int l=n+1;
for(int i=1;i<=m;i++){
while(l>q[i].l){
l--;
add(bk[l],1);
add(bk[bk[l]],-1);
}
q[i].l=query(q[i].r)-query(q[i].l-1);
}
sort(q+1,q+m+1,cmp1);
for(int i=1;i<=m;i++)printf("%d\n",q[i].l);
return 0;
}
8.little w and Discretization
每一个离散化的操作可以看成是一个区间求mex的操作,得到区间的 mex 之后,在询问这个区间比mex 大的数有多少个就是每一个询问的答案了。
首先求区间mex ,这个可以用线段树来做,线段树维护区间编号出现的最左的位置,叶子节点维护节点编号最后出现的位置。
求完mex,剩下的就简单了,询问这个区间大mex 大的数有多少个,经典题了,用权值线段树即可。
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=3e5+101;
const int MOD=998244353;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int n,a[maxn],m;
struct wzq{int l,r,mex,id;}q[maxn];
struct Tree{ //权值线段树
int cnt,rt[maxn];
Tree(){cnt=0;}
struct inf{
int lr,rc,v;
inf(){v=0;}
}tre[maxn<<5];
void build(int &k,int l,int r){
k=++cnt;
if(l==r)return ;
int mid=(l+r)>>1;
build(tre[k].lr,l,mid);build(tre[k].rc,mid+1,r);
return ;
}
void modify(int &now,int pre,int l,int r,int pos){
tre[++cnt]=tre[pre];now=cnt;tre[cnt].v++;
if(l==r)return ;
int mid=(l+r)>>1;
if(pos<=mid)modify(tre[now].lr,tre[pre].lr,l,mid,pos);
else modify(tre[now].rc,tre[pre].rc,mid+1,r,pos);
return ;
}
int query(int x,int y,int l,int r,int pos){
if(r<=pos)return tre[x].v-tre[y].v;
if(l>pos)return 0;
int mid=(l+r)>>1;
return query(tre[x].lr,tre[y].lr,l,mid,pos)+query(tre[x].rc,tre[y].rc,mid+1,r,pos);
}
}T2;
struct MEX{ // 求MEX
struct ww{
int v;
ww(){v=-1;}
}tr[maxn<<2];
void change(int k,int l,int r,int val,int pos){
if(l==r){tr[k].v=pos;return ;}
int mid=(l+r)>>1;
if(val<=mid)change(k<<1,l,mid,val,pos);
else if(val>mid)change(k<<1|1,mid+1,r,val,pos);
tr[k].v=min(tr[k<<1].v,tr[k<<1|1].v);
}
int bi_query(int k,int l,int r,int pos){
if(l==r)return l;
int mid=(l+r)>>1;
if(tr[k<<1].v<pos)return bi_query(k<<1,l,mid,pos);
else return bi_query(k<<1|1,mid+1,r,pos);
}
}T1;
int main(){
int maxx=0;
n=read();for(int i=1;i<=n;i++)a[i]=read();
m=read();for(int i=1;i<=m;i++)q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+m+1,[](wzq i,wzq j){return i.r<j.r;});
for(int i=1;i<=m;i++){
if(q[i].r!=q[i-1].r){
for(int j=q[i-1].r+1;j<=q[i].r;j++){
if(a[j]<=n)T1.change(1,1,n+1,a[j],j);
}
}
q[i].mex=T1.bi_query(1,1,n+1,q[i].l);
}
T2.build(T2.rt[0],1,n+1);
for(int i=1;i<=m;i++){
if(q[i].r!=q[i-1].r){
for(int j=q[i-1].r+1;j<=q[i].r;j++){
if(a[j]>n+1)T2.rt[j]=T2.rt[j-1];
else T2.modify(T2.rt[j],T2.rt[j-1],1,n+2,a[j]);
}
}
q[i].mex=q[i].r-q[i].l+1-T2.query(T2.rt[q[i].r],T2.rt[q[i].l-1],1,n+2,q[i].mex-1);
}
sort(q+1,q+m+1,[](wzq i,wzq j){return i.id<j.id;});
for(int i=1;i<=m;i++)printf("%d\n",q[i].mex);
return 0;
}
9.F - Sum Sum Max
简单来说,是正的就加,不是要么全加来考虑后续加减,要么不加
对所有可能取max
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=998244353;
const ll inf=2147483647;
const double pi=acos(-1);
ll read(){
ll x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
ll t,n,m;
ll x[maxn],y[maxn];
int main(){
t=read();
while(t--){
n=read();m=read();
for(int i=1;i<=n;i++)x[i]=read(),y[i]=read();
ll a=0,b=0,ans=-1E18;
for(int i=1;i<=n;i++){
ans=max(ans,b+a+x[i]);
if(x[i]<=0 && a+x[i]>=0){
ll l=0,r=y[i],ji=0;
while(r>=l){
ll mid=(l+r)>>1;
if(a+x[i]*mid>=0)l=mid+1,ji=mid;
else r=mid-1;
}
ans=max(ans,b+(a+x[i]+a+ji*x[i])*ji/2);
}
b=b+a*y[i]+1ll*x[i]*y[i]*(y[i]+1)/2;
ans=max(ans,b);
a=a+x[i]*y[i];
}
printf("%lld\n",ans);
}
return 0;
}
10.D - Sequence Query
multiset是
set和multiset的区别是后者可以存在重复的数
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<queue>
#include<set>
#define ll long long
using namespace std;
const int maxn=200000+101;
const int MOD=998244353;
const int inf=2147483647;
ll read(){
ll x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
int q;
int main(){
q=read();
multiset<ll>s;
s.insert(1000000000000000000+1);
while(q--){
int opt=read();
ll x=read();
if(opt==1){
s.insert(x);
}
else if(opt==2){
int k=read();
if(s.empty()){
printf("-1\n");continue;
}
multiset<ll>::iterator it;
it=s.upper_bound(x); //第一个大于x的数
bool fa=false;
while(k--){
if(it==s.begin()){fa=!fa;break;}
it--;
}
if(!fa)printf("%lld\n",*it);
else printf("-1\n");
}
else {
int k=read();
if(s.empty()){printf("-1\n");continue;}
multiset<ll>::iterator it;
it=s.lower_bound(x); //第一个大于等于x的数
bool fa=false;
k--;
while(k--){
if(it==s.end() || *it==1000000000000000000+1){fa=!fa;break;}
it++;
}
if((it==s.end() || *it==1000000000000000000+1)&& !fa){fa=!fa;}
if(!fa)printf("%lld\n",*it);
else printf("-1\n");
}
}
return 0;
}