【题解】【原创题目】せやな~
人々の話題:陳興玲
人々の経験の問題:\(\ {テキストYudeS} \)ダイ
题目传送门:せやな~
説明[タイトル]
質問の意味を簡素化:
[分析]
【ソリューション#1】
純粋な暴力、間隔プリアンブルが行を取る算出全ての重み\(K \)オープン注意すべき番目\(\長いロングテキストを{} \) 。
時間の複雑さ:\(O(N-2logn ^)\) 。
スコア:\(10ptの\) 。
【コード#1】
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define LL long long
#define Re register LL
using namespace std;
const LL N=1e5+5,M=1e6+5,inf=1e18,P=99999999999999997ll;
LL n,m,K,op,A[N],S[N],Ans[M];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
inline bool cmp(Re a,Re b){return a>b;}
inline void out(){
printf("%lld\n",Ans[K]);
if(op){
LL ans=0;
for(Re i=1;i<=K;++i)(ans+=(Ans[i]+P)%P)%=P;
printf("%lld\n",ans);
}
}
int main(){
// freopen("data.in","r",stdin);
in(n),in(K),in(op);
for(Re i=1;i<=n;++i)in(A[i]),S[i]=S[i-1]+A[i];
for(Re i=1;i<=n;++i)
for(Re j=1;j<=i;++j)
Ans[++m]=S[i]-S[j-1];
sort(Ans+1,Ans+m+1,cmp);
out();
}
【ソリューション#2】
有用な特性を指摘:それぞれについて\([1、N-] I \で\)に\(I \)右端点間隔、答えが超えない貢献しなければならない(\ Kを\ ) A。
最初の\(O(nlogn)\)前処理アレイ\(NEX \) 、\(NEX [I] \)の比を表し\(I \)同一のに対して取られている場合、位置の最小のものを多数左。
(1 \)\に\(N- \)列挙\(I \) 、それぞれについて\(I \)使用されている\(NEX \)暴れ波、もし位置\(J \)で\( I \)左は、置く(\ S [i]が-S [ J] \) キューに追加されました\(B_1 \)キューに、そして答え\(ANS \) 、見つかったキューに新しい回答に\(B_1を、ANSは\)単調挙動、直接である\(O(K)\)にマージ。
各指標については、最も可能性の高い移動する\(O(N)\)回、それはに位置しています(私は\)\より左(K \)を\際に1時間複雑分析はについては、非常に良いではありませんので、停止しますある\(O(K \ N-SIM)\) 。私はこの練習のカードを出て行く、だけおそらくカードの下に、多くの場合、複数の水ポイントを持つことができ、データは自分のコードを持っていない作られていませんでしたか?
時間の複雑さ:\(O(nlogn +(NK \ SIM ^ N-2)+ NK)\) 。
スコア:\(25pt \ thicksim 40pt \) 。
【コード#2-1】
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define LL long long
#define Re register LL
using namespace std;
const LL N=1e5+5,M=1000+5,inf=1e18,P=99999999999999997ll;
LL n,m,K,op,A[N],S[N],B1[M],B2[M],nex[N],Ans[M];
struct QAQ{
LL x,v;QAQ(LL X=0,LL V=0){x=X,v=V;}
inline bool operator<(const QAQ &O)const{return v!=O.v?v<O.v:x<O.x;}
}b[N];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
inline int merge(Re *P,Re *A,Re t1,Re *B,Re t2){//归并
Re t=0,p1=1,p2=1;A[t1+1]=B[t2+1]=-inf;
while(t<K&&(p1<=t1||p2<=t2))//注意t>=K时要停止
if(A[p1]>B[p2])P[++t]=A[p1++];
else P[++t]=B[p2++];
return t;
}
inline void out(){
printf("%lld\n",Ans[K]);
if(op){
LL ans=0;
for(Re i=1;i<=K;++i)(ans+=(Ans[i]+P)%P)%=P;
printf("%lld\n",ans);
}
}
int main(){
// freopen("data.in","r",stdin);
in(n),in(K),in(op);
for(Re i=1;i<=n;++i)in(A[i]),S[i]=S[i-1]+A[i];
for(Re i=0;i<=n;++i)b[++m]=QAQ(i,S[i]);
sort(b+1,b+m+1);//从小到大排序
nex[b[m].x]=n+1;//注意边界
for(Re i=m-1;i>=1;--i)nex[b[i].x]=b[i+1].x;
for(Re i=1;i<=n;++i){
Re t1=0,t2=Ans[0];Ans[0]=0;
for(Re j=b[1].x;t1<K&&j!=n+1;j=nex[j])
if(j<i)B1[++t1]=S[i]-S[j];//从大到小存进去
for(Re j=1;j<=t2;++j)B2[j]=Ans[j];
Ans[0]=merge(Ans,B1,t1,B2,t2);
}
out();
}
[最適化]
上記削除検討({N O(\ FRACを\ ^ 2} {\テキスト{ 形而上}})\)ポインタ移動。
ため\(I \) 、あればフロントを取得ほど左(K \)\小(S [J] \)\それがなることができる前に、\(K \)大\(S [I ] -S [J] \) 。以前に使用\(B_1 \)私たちは店にそれを使用している場合は、重量範囲を保つ\(S [J] \)それは?
とき\(I \)とき、後方シフト、我々が見つかりました\(B_ {1} \)の要素のほとんどはしなかった変更を、より多くの\(S [I-1] \) 、によってバイナリ列挙または私達は位置に挿入♂見つけること、そしてそれがになります必要があります。
上述した動作とすることができる\(O(K)\)実装。
時間の複雑さ:\(O(NK)\) 。
スコア:\(40pt \) 。
【コード#2-2】
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define LL long long
#define Re register LL
using namespace std;
const LL N=1e5+5,M=1000+5,inf=1e18,P=99999999999999997ll;
LL n,m,K,op,t1,t2,A[N],S[N],Q[M],B1[M],B2[M],nex[N],Ans[M];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
inline int merge(Re *P,Re *A,Re t1,Re *B,Re t2){//归并
Re t=0,p1=1,p2=1;A[t1+1]=B[t2+1]=-inf;
while(t<K&&(p1<=t1||p2<=t2))
if(A[p1]>B[p2])P[++t]=A[p1++];
else P[++t]=B[p2++];
return t;
}
inline void out(){
printf("%lld\n",Ans[K]);
if(op){
LL ans=0;
for(Re i=1;i<=K;++i)(ans+=(Ans[i]+P)%P)%=P;
printf("%lld\n",ans);
}
}
int main(){
// freopen("data.in","r",stdin);
in(n),in(K),in(op);
for(Re i=1;i<=n;++i)in(A[i]),S[i]=S[i-1]+A[i];
for(Re i=1;i<=n;++i){
if(t1<K)Q[++t1]=inf;//如果还没有K个,增加一个位置
for(Re j=1;j<=t1;++j)
if(S[i-1]<Q[j]){//找到需要插♂入的位置
for(Re k=t1-1;k>=j;--k)Q[k+1]=Q[k];//后面整体向后移一位腾出位置
Q[j]=S[i-1];break;//插♂入S[i-1]
}
Re t2=Ans[0];
for(Re j=1;j<=t1;++j)B1[j]=S[i]-Q[j];
for(Re j=1;j<=t2;++j)B2[j]=Ans[j];
Ans[0]=merge(Ans,B1,t1,B2,t2);
}
out();
}
【ソリューション#3】
特別な性質\(1 \。):\ (\ FORALL I \で、\ [1、N - 。]) \(A_ {I} \ geqslant 0 \) 。
\(A_ {I} \)より大きい(0 \)\、用途は何ですか?
重みの範囲のいずれかは、必ずしもそのサブインターバルの重みより小さくありません。
最大間隔でなければならない([1、N] \ \ ) まず、([1、N] \ \ ) 大根重スタック部の並び替えスロー。連続的にスタック要素の上部を占有\(K \)回、次いで部から取り出さ\([L、R] \ ) となる([L、R-1 \ ] \) と、L + 1 [(\ R] \)に投げます。
そのノート\([L + 1、R ] \) と\([L、R-1 ] \) 有するように思われる\([Lの+。1 ,. 1-R&LT] \)を、それが決定されるたびに添加そのこの間隔があまりにも追加されているかどうか。
時間の複雑さ:\(O(KlogK)\) 。
スコア:\(10ptの\) 、アルゴリズムを組み合わせることができる前に\(50pt \) 。
【コード#3-1】
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<map>
#define LL long long
#define Re register LL
#define mp make_pair
using namespace std;
const LL N=1e5+6,M=1e6+5,inf=1e18,P=99999999999999997ll;
LL n,K,op,flag=1,A[N],S[N],Ans[M];
struct QAQ{
LL l,r,v;QAQ(LL L=0,LL R=0){v=S[r=R]-S[(l=L)-1];}
inline bool operator<(const QAQ &O)const{return v<O.v;}
};
priority_queue<QAQ>Q;map<pair<LL,LL>,bool>pan;
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
inline void sakura(){//求前K大
Q.push(QAQ(1,n));
while(Ans[0]<K){
QAQ x=Q.top();Q.pop();
Ans[++Ans[0]]=x.v;
if(x.l!=x.r){
if(!pan[mp(x.l,x.r-1)])pan[mp(x.l,x.r-1)]=1,Q.push(QAQ(x.l,x.r-1));
if(!pan[mp(x.l+1,x.r)])pan[mp(x.l+1,x.r)]=1,Q.push(QAQ(x.l+1,x.r));
}
}
}
inline void out(){
printf("%lld\n",Ans[K]);
if(op){
LL ans=0;
for(Re i=1;i<=K;++i)(ans+=(Ans[i]+P)%P)%=P;
printf("%lld\n",ans);
}
}
int main(){
// freopen("data.in","r",stdin);
in(n),in(K),in(op);
for(Re i=1;i<=n;++i)in(A[i]),S[i]=S[i-1]+A[i],flag&=(A[i]>=0);
if(flag){sakura(),out();return 0;}
}
改善されたアルゴリズム[]
どのように上記のアルゴリズムの一般化を検討してください。
同様のスーパーピアノ(\ \テキスト{[NOI2010] [P2048]} \)大ルートスタックメンテナンスクワッドと、\(\ {X、L、R&LT、T \} \) 、\(Tは\)間隔である\ ([L、R] \)最大プレフィクスおよび\(S \)位置は、それがすることができる\(ST \)表前処理。応じて、スタック(S [T] -S [X ] \)\ 同様の順序。
それぞれについて、(I \)\、\(\ {I、I、 N、T \} \) に従うこと大ルートヒープを添加した(S [T] -S [X ] \)\ 同様の順序。スタックの最上位に各要素を削除して間隔を取り出し\([L、R] \ ) となる([L、T-1 \ ] \) と\([T + 1、R ] \) リストに再追加。
コードは超簡単です。
時間の複雑さ:\(O(nlogn + KlogK)\) 。
スコア:\(70pt \) 。
【コード#3-2】
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define LL long long
#define Re register int
using namespace std;
const LL N=1e5+5,M=1e6+5,logN=17,inf=1e18,P=99999999999999997ll;
int n,K,op,A[N],lg[N],f[N][18];LL S[N],Ans[M];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
inline int Max(Re a,Re b){return S[a]>S[b]?a:b;}
inline int ask(Re L,Re R){Re m=lg[R-L+1];return Max(f[L][m],f[R-(1<<m)+1][m]);}
struct QAQ{
int x,t,l,r;QAQ(int X=0,int L=0,int R=0){x=X,t=ask(l=L,r=R);}
inline bool operator<(const QAQ &O)const{return S[t]-S[x-1]<S[O.t]-S[O.x-1];}
};
priority_queue<QAQ>Q;
inline void out(){
printf("%lld\n",Ans[K]);
if(op){
LL ans=0;
for(Re i=1;i<=K;++i)(ans+=(Ans[i]+P)%P)%=P;
printf("%lld\n",ans);
}
}
int main(){
// freopen("data.in","r",stdin);
in(n),in(K),in(op),lg[0]=-1;
for(Re i=1;i<=n;++i)in(A[i]),S[f[i][0]=i]=S[i-1]+A[i],lg[i]=lg[i>>1]+1;
for(Re j=1;j<=logN;++j)
for(Re i=1;i+(1<<j)-1<=n;++i)
f[i][j]=Max(f[i][j-1],f[i+(1<<j-1)][j-1]);
for(Re i=1;i<=n;++i)Q.push(QAQ(i,i,n));
while(Ans[0]<K){
QAQ x=Q.top();Q.pop();
Ans[++Ans[0]]=S[x.t]-S[x.x-1];
if(x.t!=x.l)Q.push(QAQ(x.x,x.l,x.t-1));
if(x.t!=x.r)Q.push(QAQ(x.x,x.t+1,x.r));
}
out();
}
【ソリューション#4】
特殊な性質\(2 \) :ちょうど要求出力\(K \)大規模な範囲、出力しないの前に\(K \)の重みと大規模な範囲。
最初の探している\(K \)は半分ああを持っている可能性が!
バイナリ\(限界\) 、各計算値よりも大きいか等しい重みである\(限界\)でない場合は以下のセクションの数、(\ K)\下部上限またはトーン、結合を調整します。
\(裁判官\)渡さ従事するためにどんなデータ構造のホールドを取得するための機能が、それでも非常に明白な\(\ {テキストCDQ} \ ) ボードが、同じ複雑さ、離散\(+ \)フェンウィックツリーへ二倍の速さ。
あなたはフェンウィックツリーを書き込むことはできません注意してください(裁判官\)\関数の離散化、より多くのために別の方法で理由もなく\(O(logN個)\) 、起因する\(S \)配列ですマイナス(プラス)\ (上限\)変わらない関係をランク付けした後は、早期に前処理をすることが可能である\(S \)を得るために、ランキング\(S \)をマイナス(プラス)\(上限\)ランキングは後に、マージ一緒に個別の最終順位を使用して2つの部分。
時間の複雑さ:\(O(nlognloginf)\) 。
スコア:\(10ptの\) 、アルゴリズムを組み合わせることができる前に\(80 PT \) 。
【コード#4-1】
(これは、ツリーアレイに書き込まれる、\(\テキストCDQ} {\)以下とアプローチ(\テキスト{コード#4-3 \ \)} まとめ)
#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register LL
using namespace std;
const LL N=1e6+5,M=1e6+5,inf=1e18,P=99999999999999997ll;
LL n,m,K,op,Ans0,Max,Min,A[N],S[N],rk[N][2];
struct QAQ{
LL i,S,rk;bool o;
inline bool operator<(const QAQ &O)const{return S<O.S;}
}S1[N],S2[N],S0[N];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
struct BIT{
LL n,C[N<<1];
inline void CL(Re m){n=m;for(Re i=1;i<=n;++i)C[i]=0;}
inline void add(Re x){while(x<=n)++C[x],x+=x&-x;}
inline LL ask(Re x){Re ans=0;while(x)ans+=C[x],x-=x&-x;return ans;}
}T1;
inline LL merge_(QAQ *P,QAQ *A,Re t1,QAQ *B,Re t2){//归并
Re t=0,t_=0,p1=1,p2=1;A[t1+1].S=B[t2+1].S=inf;
while((p1<=t1||p2<=t2))
if(A[p1].S<B[p2].S)P[++t]=A[p1++];
else P[++t]=B[p2++];
for(Re i=1;i<=t;++i){
if(i<2||P[i].S!=P[i-1].S)++t_;
P[i].rk=t_;
}
return t_;
}
inline LL judge(Re mid){
for(Re i=1;i<=m;++i)S2[i]=S1[i],S2[i].S-=mid,S2[i].o=1;//S1本身有序,S1.S[i]均减去mid后依然有序
Re tmp=0,t_=merge_(S0,S1,m,S2,m);T1.CL(t_);//把两个有序的S1,S2合成一个S0,可以直接归并
for(Re i=1;i<=(m<<1);++i)rk[S0[i].i][S0[i].o]=S0[i].rk;//获得排名
for(Re i=1;i<=n&&tmp<K;++i)T1.add(rk[i-1][0]),tmp+=T1.ask(rk[i][1]);//统计大于等于mid的区间数量
return tmp>=K;
}
int main(){
// freopen("data.in","r",stdin);
in(n),in(K),in(op);
for(Re i=1,Mi=0,Ma=0;i<=n;++i)
in(A[i]),S[i]=S[i-1]+A[i],
Max=max(Max,S[i]-Mi),Mi=min(Mi,S[i]),
Min=min(Min,S[i]-Ma),Ma=max(Ma,S[i]);
for(Re i=0;i<=n;++i)S1[++m]=(QAQ){i,S[i]};
sort(S1+1,S1+m+1);//让S1有序
Re l=Min,r=Max;//卡一下常数
while(l<r){
Re mid=l+r+1>>1;
if(judge(mid))l=mid;
else r=mid-1;
}
printf("%lld\n",Ans0=l);
}
改善されたアルゴリズム[]
特殊性を解決\(2 \) 、正の解が自然に出てきます。
最初の計算最初の\(K \)パワー値\(Ans_0 \) 。
依然としてオン(\テキスト{CDQ} \ \ ) ボード:重みは、より厳密に大きい計算される(Ans_0 \)\間隔と重み。
最後に結合された\(Ans_0 \) \(\タイムズ\) (- K- \)\(より大きいか等しい重み\(Ans_0 + 1 \)セクション番号(\)\) 。
時間の複雑さ:\(O(nlognloginf + nlogn)\) 。
スコア:\(100pt \) 。
【コード#4-2】
(フェンウィックツリー\(裁判官\) )
#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register LL
using namespace std;
const LL N=1e5+5,inf=1e18,P=99999999999999997ll;
LL n,m,K,op,Max,Min,Ans0,Ans1,A[N],S[N],S_[N],rk[N][2];
struct QAQ{
LL i,S,rk;bool o;
inline bool operator<(const QAQ &O)const{return S<O.S;}
}S1[N],S2[N],S0[N<<1];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
struct BIT{
LL n,C[N<<1];
inline void CL(Re m){n=m;for(Re i=1;i<=n;++i)C[i]=0;}
inline void add(Re x){while(x<=n)++C[x],x+=x&-x;}
inline LL ask(Re x){Re ans=0;while(x)ans+=C[x],x-=x&-x;return ans;}
}T1;
inline LL merge_(QAQ *P,QAQ *A,Re t1,QAQ *B,Re t2){//归并
Re t=0,t_=0,p1=1,p2=1;A[t1+1].S=B[t2+1].S=inf;
while((p1<=t1||p2<=t2))
if(A[p1].S<B[p2].S)P[++t]=A[p1++];
else P[++t]=B[p2++];
for(Re i=1;i<=t;++i){
if(i<2||P[i].S!=P[i-1].S)++t_;
P[i].rk=t_;
}
return t_;
}
inline LL judge(Re mid){
for(Re i=1;i<=m;++i)S2[i]=S1[i],S2[i].S-=mid,S2[i].o=1;//S1本身有序,S1.S[i]均减去mid后依然有序
Re tmp=0,t_=merge_(S0,S1,m,S2,m);T1.CL(t_);//把两个有序的S1,S2合成一个S0,可以直接归并
for(Re i=1;i<=(m<<1);++i)rk[S0[i].i][S0[i].o]=S0[i].rk;//获得排名
for(Re i=1;i<=n&&tmp<K;++i)T1.add(rk[i-1][0]),tmp+=T1.ask(rk[i][1]);//统计大于等于mid的区间数量
return tmp;
}
inline void merge(Re *P,Re p1,Re t1,Re p2,Re t2){//归并
Re t=p1-1;
while((p1<=t1||p2<=t2))
if((p1<=t1&&S[p1]<S[p2])||p2>t2)P[++t]=S[p1++];//注意判断是否大于t1,t2
else P[++t]=S[p2++];
}
inline void CDQ(Re L,Re R){
if(L==R)return;
Re mid=L+R>>1,p1=L-1,p2=mid+1,SL=0;
CDQ(L,mid),CDQ(mid+1,R);
while(p2<=R){
while(p1<mid&&S[p2]-S[p1+1]>Ans0)SL+=S[++p1];//移左指针
(Ans1+=(S[p2++]*(p1-L+1)-SL+P)%P)%=P;//右指针一位一位地移
}
merge(S_,L,mid,mid+1,R);//归并排序
for(Re i=L;i<=R;++i)S[i]=S_[i];
}
int main(){
// freopen("data.in","r",stdin);
in(n),in(K),in(op);
for(Re i=1,Mi=0,Ma=0;i<=n;++i)
in(A[i]),S[i]=S[i-1]+A[i],
Max=max(Max,S[i]-Mi),Mi=min(Mi,S[i]),
Min=min(Min,S[i]-Ma),Ma=max(Ma,S[i]);
for(Re i=0;i<=n;++i)S1[++m]=(QAQ){i,S[i]};
sort(S1+1,S1+m+1);//让S1有序
Re l=Min,r=Max;//卡一下常数
while(l<r){
Re mid=l+r+1>>1;
if(judge(mid)>=K)l=mid;
else r=mid-1;
}
printf("%lld\n",Ans0=l);
if(op){
K-=judge(Ans0+1),CDQ(0,n);
printf("%lld\n",(Ans1+K*Ans0%P)%P);//其实K*Ans0是有可能会炸的(10^19),懒得写龟速乘和专门出数据了
}
}
【コード#4-3】
( \(\ テキスト{CDQ} \) \(裁判官\) )
#include<algorithm>
#include<cstring>
#include<cstdio>
#define LL long long
#define Re register LL
using namespace std;
const LL N=1e5+5,inf=1e18,P=99999999999999997ll;
LL n,m,K,op,tmp,Max,Min,Ans0,Ans1,A[N],S[N],S_[N],S__[N];
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
inline void merge_(Re *P,Re p1,Re t1,Re p2,Re t2){//归并
Re t=p1-1;
while((p1<=t1||p2<=t2))
if((p1<=t1&&S_[p1]<S_[p2])||p2>t2)P[++t]=S_[p1++];//注意判断是否大于t1,t2
else P[++t]=S_[p2++];
}
inline void CDQ_(Re L,Re R,Re limit){
if(L==R)return;
Re mid=L+R>>1,p1=L-1,p2=mid+1;
CDQ_(L,mid,limit),CDQ_(mid+1,R,limit);
while(p2<=R){
while(p1<mid&&S_[p2]-S_[p1+1]>=limit)++p1;//移左指针
tmp+=p1-L+1,++p2;//右指针一位一位地移
}
merge_(S__,L,mid,mid+1,R);//归并排序
for(Re i=L;i<=R;++i)S_[i]=S__[i];
}
inline LL judge(Re mid){
tmp=0;
for(Re i=0;i<=n;++i)S_[i]=S[i];
CDQ_(0,n,mid);
return tmp;
}
inline void merge(Re *P,Re p1,Re t1,Re p2,Re t2){//归并
Re t=p1-1;
while((p1<=t1||p2<=t2))
if((p1<=t1&&S[p1]<S[p2])||p2>t2)P[++t]=S[p1++];//注意判断是否大于t1,t2
else P[++t]=S[p2++];
}
inline void CDQ(Re L,Re R){
if(L==R)return;
Re mid=L+R>>1,p1=L-1,p2=mid+1,SL=0;
CDQ(L,mid),CDQ(mid+1,R);
while(p2<=R){
while(p1<mid&&S[p2]-S[p1+1]>Ans0)SL+=S[++p1];//移左指针
(Ans1+=(S[p2++]*(p1-L+1)-SL+P)%P)%=P;//右指针一位一位地移
}
merge(S_,L,mid,mid+1,R);//归并排序
for(Re i=L;i<=R;++i)S[i]=S_[i];
}
int main(){
// freopen("data.in","r",stdin);
in(n),in(K),in(op);
for(Re i=1,Mi=0,Ma=0;i<=n;++i)
in(A[i]),S[i]=S[i-1]+A[i],
Max=max(Max,S[i]-Mi),Mi=min(Mi,S[i]),
Min=min(Min,S[i]-Ma),Ma=max(Ma,S[i]);
Re l=Min,r=Max;//卡一下常数
while(l<r){
Re mid=l+r+1>>1;
if(judge(mid)>=K)l=mid;
else r=mid-1;
}
printf("%lld\n",Ans0=l);
if(op){
K-=judge(Ans0+1),CDQ(0,n);
printf("%lld\n",(Ans1+K*Ans0%P)%P);//其实K*Ans0是有可能会炸的(10^19),懒得写龟速乘和专门出数据了
}
}
[一部]余談
おかげで\(\ {テキストYudeS} \ ) ダイは、提案された\(\ \ {コード#3-2 }テキスト)を、実際に。
この質問は、テスト中に退屈な退屈さ\(YY \)アウト。