在RP守恒定律的持续作用下,

不出所料,这场稍炸

还有10分钟就是下一场了,但愿继续守恒?

改题太慢了,连写博的时间都没有了

然而最后还是在吃饭前彻彻底底改出来了

的确是个菜鸡

所以今天的题解只能先咕了

晚上加油

1012upd:RP守恒,breaked

下一篇反思再说。

但是这套题有不少要反思的。

T1打的是错解但是用了各种技巧让小点必然正确大点有概率正确。

T2沉迷测试点分治为了那4分9分的玩意浪费的大量的时间,最后只调出来了暴力,很多子任务都没有调,也就没有分。

但是其实T2已经想到伪正解了(会被卡常)但是感觉会很难码而且时间不多就扔了(其实也就是不会主席树查前驱后继)

其实就算把分治打满也就55分。明显因小失大。

但是因为大量的时间浪费在这上面了,T3我只留了25分钟左右。

快速的码完暴力,快速的想到75分做法,但是没有时间打了。

不要沉迷测试点分治,要在相同的时间内得尽量多的分数。

一定要给每一道题留下充足的时间,不要想到高分算法但是没时间打。

注意分数与时间的关系。

T1:d

不满足三分性质。但是可以大概乱打一下。这样就能保证小的子任务不失分了。

 #include<cstdio>
#include<algorithm>
using namespace std;
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
struct rec{int x,y,id;}rx[],ry[];
bool X(rec a,rec b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
bool Y(rec a,rec b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}
int n,m;long long ans;char ald[];
long long chk(int x){
int res=m-x;long long fy;//printf("%d\n",x);
for(int i=;i<=x;++i)ald[rx[i].id]=;
for(int i=;i<=n;++i)if(!ald[ry[i].id]&&!res){fy=ry[i].y;break;}else if(!ald[ry[i].id])res--;
for(int i=;i<=x;++i)ald[rx[i].id]=;//printf("%lld\n",fy);
if(rx[x+].x*fy>ans)ans=rx[x+].x*fy;return rx[x+].x*fy;
}
int main(){//freopen("d2.in","r",stdin);freopen("my.out","w",stdout);
int t=read();
while(t--){
n=read(),m=read();
for(int i=;i<=n;++i)rx[i].x=read(),rx[i].y=read(),rx[i].id=i,ry[i]=rx[i];
sort(rx+,rx++n,X);sort(ry+,ry++n,Y);
int l=,r=m;ans=;
if(n-==m){
for(int i=;i<=n;++i)if(1ll*rx[i].x*rx[i].y>ans)ans=1ll*rx[i].x*rx[i].y;
goto A;
}
if(rx[].x==rx[n].x){ans=1ll*ry[m+].y*rx[].x;goto A;}
while(l<r-){
long long ansl=chk(l+r>>),ansr=chk((l+r>>)+);
if(ansl<ansr)l=l+r>>;
else if(ansr<ansl)r=(l+r>>)+;
else{break;
ansl=chk(l+(r-l)/),ansr=chk(l+(r-l)*/);
if(ansl<ansr)l=l+(r-l)/;
else if(ansr>ansl)r=l+(r-l)*/;
else break;
}
}
for(;l<=r;++l)chk(l);
A: printf("%lld\n",ans);
}
}

有一点用的乱搞81分

思路其实差不多,当然费用与“删除的x最小的矩形个数”相关。

关键是删除x最小的矩形的同时有一些y最小的也同时被删除了。

那么还要继续删掉几个,怎么知道要删哪些呢?

从大到小枚举x最小的矩形删除个数,这样的话每次会加入一个矩形。

然后同时,你可以多删除一个矩形,删除y最小的一个。

随便一个堆就可以满足这种“单个加入,取出并删除最小”的要求了

 #include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
struct rec{
int x,y;
friend bool operator<(rec a,rec b){
return a.y>b.y;
}
}rx[];
priority_queue<rec>q;
bool X(rec a,rec b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
int n,m;long long ans;
int main(){//freopen("d2.in","r",stdin);freopen("my.out","w",stdout);
int t=read();
while(t--){
n=read(),m=read();ans=;while(!q.empty())q.pop();
for(int i=;i<=n;++i)rx[i].x=read(),rx[i].y=read();
sort(rx+,rx++n,X);
for(int i=m+;i<=n;++i)q.push(rx[i]);
for(int i=m;~i;--i)ans=max(ans,1ll*rx[i+].x*q.top().y),q.push(rx[i]),q.pop();
printf("%lld\n",ans);
}
}

思路积累:

  • 转换题意
  • 正难则反
  • 根据要求选择数据结构

T2:e

纪念一下愚蠢的测试点分治的冗长的调了两小时还没什么分的代码。

 //subtask1-2:violence
//subtask3:ans=|a-r|
//subtask4:ans=|ap-r|
//subtask5:tree*10
//subtask6:min-1
//subtask7-8:2B_balanced_tree?
//subtask9:return 0
//subtask10:2B_balanced_tree?
#include<cstdio>
#include<iostream>
#include<vector>
using namespace std;
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
int n,q,type,fir[],l[],to[],cnt,a[],r[],k[];
vector<int>v[];
void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;}
int _abs(int x){return x>?x:-x;}
int dep[],f[][],ap[][][],mn[][];
int mxk=,mxr=,mxa=,mna=;
void dfs(int p,int fa){
dep[p]=dep[fa]+;f[p][]=fa;if(mxa<=)ap[p][][a[p]]=;mn[p][]=a[p];
for(int i=;i<=;++i){
f[p][i]=f[f[p][i-]][i-];mn[p][i]=min(mn[p][i],mn[f[p][i-]][i-]);
if(mxa<=)for(int j=;j<=;++j)ap[p][i][j]=ap[p][i-][j]|ap[f[p][i-]][i-][j];
}
for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dfs(to[i],p);
}
int lca(int a,int b){
int sub=dep[a]-dep[b];
if(sub<)sub=-sub,a^=b^=a^=b;
for(int i=;~i;--i)if(sub&<<i)a=f[a][i];//printf("%d %d\n",dep[a],dep[b]);
if(a==b)return a;
for(int i=;~i;--i)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];//,printf("in lca:%d %d %d %d\n",a,b,f[a][0],f[b][0]);
return f[a][];
}
namespace subtask1_2_7_8_10{
int ald[];
void main(){
for(int i=;i<=q;++i){
int LCA=v[i][],ans=;
for(int j=;j<k[i];++j)LCA=lca(LCA,v[i][j]);//,printf("LCA:%d\n",LCA);
for(int j=;j<k[i];++j){
int p=v[i][j];
while(ald[p]!=i&&p!=LCA)ans=min(ans,_abs(a[p]-r[i])),ald[p]=i,p=f[p][];//,printf("%d\n",p);
}
printf("%d\n",min(ans,_abs(a[LCA]-r[i])));
}
}
}
namespace subtask3{
void main(){
for(int i=;i<=q;++i)printf("%d\n",_abs(a[]-r[i]));
}
}
namespace subtask4{
void main(){
for(int i=;i<=q;++i)printf("%d\n",_abs(a[v[i][]]-r[i]));
}
}
namespace subtask5{
void main(){
int alp[];
for(int i=;i<=q;++i){
int LCA=v[i][],ans=;
for(int j=;j<k[i];++j)LCA=lca(LCA,v[i][j]);
for(int j=;j<k[i];++j){
int sub=dep[v[i][j]]-dep[LCA]+,p=v[i][j];
for(int i=;~i;--i)if(sub&<<i){
for(int j=;j<=;++j)if(ap[p][i][j])alp[j]=i;
p=f[p][i];
}
}
for(int j=;j<=;++j)if(alp[j]==i)ans=min(ans,_abs(r[i]-j));
printf("%d\n",ans);
}
}
}
namespace subtask6{
void main(){
for(int i=;i<=q;++i){
int LCA=v[i][],ans=;
for(int j=;j<k[i];++j)LCA=lca(LCA,v[i][j]);
for(int j=;j<k[i];++j){
int sub=dep[v[i][j]]-dep[LCA]+,p=v[i][j];
for(int i=;~i;--i)if(sub&<<i)ans=min(ans,mn[p][i]-),p=f[p][i];
}
printf("%d\n",ans);
}
}
}
namespace subtask9{
void main(){
return;
}
}
int main(){//freopen("e2.in","r",stdin);freopen("my.out","w",stdout);
n=read();q=read();type=read();
for(int i=;i<=n;++i)mxa=max(mxa,a[i]=read()),mna=min(mna,a[i]);
for(int i=,x,y;i<n;++i)x=read(),y=read(),link(x,y),link(y,x);
for(int i=;i<=q;++i){
mxr=max(mxr,r[i]=read());mxk=max(mxk,k[i]=read());
for(int j=;j<=k[i];++j)v[i].push_back(read());
}
dfs(,);
if(n<=)subtask1_2_7_8_10::main();
else if(mxa==mxa)subtask3::main();
else if(mxk==)subtask4::main();
else if(mxa<=&&mxr<=)subtask5::main();
else if(mxr==)subtask6::main();
else if(q==)subtask9::main();
else subtask1_2_7_8_10::main();
}

绝对值。容易转换为查前驱后继。

第一反应:平衡树上树。

第二反应:主席树上树。

哪个好打一些还是比较明显的。在除了区间翻转的情况以外大多数时候主席树都可以替代平衡树,码量也小也好调。

既然问链,那么首先一个草率的思路就是老套路树炼剖分。

但是其实想一下,这道题并不用维护子树,而是只维护链即可,所以这样的话不必按照DFS序建树。

直接让儿子继承父亲的主席树即可。

但是最后我打的还是第一种思路。多一个log。

 #include<cstdio>
#include<iostream>
using namespace std;
#define inf 1000000000
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
int n,q,ans,type,a[],res[],r,k;
int fir[],l[],to[],cnt,f[];
int w[],pc,rt[],lc[],rc[];
int siz[],hson[],top[],dfn[];
int re[],dep[],tim;
void link(int x,int y){l[++cnt]=fir[x];fir[x]=cnt;to[cnt]=y;}
//主席树
void insert(int &p,int cpy,int l,int r,int v){
p=++pc;w[p]=w[cpy]+;
if(l==r)return;
if(v<=l+r>>)insert(lc[p],lc[cpy],l,l+r>>,v),rc[p]=rc[cpy];
else insert(rc[p],rc[cpy],(l+r>>)+,r,v),lc[p]=lc[cpy];
}
void build(){for(int i=;i<=n;++i)insert(rt[i],rt[i-],,inf,a[re[i]]);}
int pre_ask(int pl,int pr,int pos,int l,int r){
if(w[pr]==w[pl])return -inf;
if(l==r)return l;
if((l+r>>)+<=pos){int x=pre_ask(rc[pl],rc[pr],pos,(l+r>>)+,r);if(x!=-inf)return x;}
return pre_ask(lc[pl],lc[pr],pos,l,l+r>>);
}
int suc_ask(int pl,int pr,int pos,int l,int r){
if(w[pr]==w[pl])return inf*;
if(l==r)return l;
if(pos<=l+r>>){int x=suc_ask(lc[pl],lc[pr],pos,l,l+r>>);if(x!=inf*)return x;}
return suc_ask(rc[pl],rc[pr],pos,(l+r>>)+,r);
}
//树链剖分
void dfs(int p,int fa){
siz[p]=;dep[p]=dep[fa]+;f[p]=fa;
for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
dfs(to[i],p);
siz[p]+=siz[to[i]];
if(siz[to[i]]>siz[hson[p]])hson[p]=to[i];
}
}
void DFS(int p,int fa,int tp){//printf("dfn:%d\n",p);
dfn[p]=++tim;top[p]=tp;re[tim]=p;
if(hson[p])DFS(hson[p],p,tp);
for(int i=fir[p];i;i=l[i])if(to[i]!=fa&&to[i]!=hson[p])DFS(to[i],p,to[i]);
}
int lca(int a,int b){
while(top[a]!=top[b])if(dep[top[a]]>dep[top[b]])a=f[top[a]];else b=f[top[b]];
return dep[a]<dep[b]?a:b;
}
int upd(int p,int anc,int r){
while(top[p]!=top[anc])ans=min(ans,min(r-pre_ask(rt[dfn[top[p]]-],rt[dfn[p]],r,,inf),suc_ask(rt[dfn[top[p]]-],rt[dfn[p]],r,,inf)-r)),p=f[top[p]];
ans=min(ans,min(r-pre_ask(rt[dfn[anc]-],rt[dfn[p]],r,,inf),suc_ask(rt[dfn[anc]-],rt[dfn[p]],r,,inf)-r));
}
int main(){//freopen("e2.in","r",stdin);freopen("my.out","w",stdout);
n=read();q=read();type=read();
for(int i=;i<=n;++i)a[i]=read();
for(int i=,x,y;i<n;++i)x=read(),y=read(),link(x,y),link(y,x);
dfs(,);DFS(,,);build();
while(q--){
r=read();k=read();
for(int i=;i<=k;++i)res[i]=(read()-+ans*type)%n+;
int LCA=res[];
for(int i=;i<=k;++i)LCA=lca(LCA,res[i]);//cout<<"LCA:"<<LCA<<endl;
ans=;
for(int i=;i<=k;++i)upd(res[i],LCA,r);//,printf("%d\n",ans);
printf("%d\n",ans);
}
}

TLE89

值域1e9过于冗余了。所以需要离散化。

我的做法是在离散化数组最前面加-inf,最后面加一个inf和一个2inf。

因为询问时的r值需要lower_bound,找到的是一个后继,后继的前驱(含自身)不一定就是前驱。

细节比较多。

其实也可以把询问的r值也离散化下来这样就没有那么多锅了,幸亏这题没有把r强制在线。

然而如果打只有一个log的思路其实就不用这么麻烦的离散化了。

 #include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
#define inf 1000000000
#define S 100000
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
int n,q,ans,type,a[],res[],r,k;
int fir[],l[],to[],cnt,f[];
int w[],pc,rt[],lc[],rc[];
int siz[],hson[],top[],dfn[];
int re[],dep[],tim;
int x[],numcnt,ref[];
map<int,int>M;
void link(int x,int y){l[++cnt]=fir[x];fir[x]=cnt;to[cnt]=y;}
//主席树
void insert(int &p,int cpy,int l,int r,int v){
p=++pc;w[p]=w[cpy]+;
if(l==r)return;
if(v<=l+r>>)insert(lc[p],lc[cpy],l,l+r>>,v),rc[p]=rc[cpy];
else insert(rc[p],rc[cpy],(l+r>>)+,r,v),lc[p]=lc[cpy];
}
void build(){for(int i=;i<=n;++i)insert(rt[i],rt[i-],,numcnt,a[re[i]]);}
int pre_ask(int pl,int pr,int pos,int l,int r){
if(w[pr]==w[pl])return ;
if(l==r)return l;
if((l+r>>)+<=pos){int x=pre_ask(rc[pl],rc[pr],pos,(l+r>>)+,r);if(x)return x;}
return pre_ask(lc[pl],lc[pr],pos,l,l+r>>);
}
int suc_ask(int pl,int pr,int pos,int l,int r){
if(w[pr]==w[pl])return numcnt;
if(l==r)return l;
if(pos<=l+r>>){int x=suc_ask(lc[pl],lc[pr],pos,l,l+r>>);if(x!=numcnt)return x;}
return suc_ask(rc[pl],rc[pr],pos,(l+r>>)+,r);
}
//树链剖分
void dfs(int p,int fa){
siz[p]=;dep[p]=dep[fa]+;f[p]=fa;
for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
dfs(to[i],p);
siz[p]+=siz[to[i]];
if(siz[to[i]]>siz[hson[p]])hson[p]=to[i];
}
}
void DFS(int p,int fa,int tp){//printf("dfn:%d\n",p);
dfn[p]=++tim;top[p]=tp;re[tim]=p;
if(hson[p])DFS(hson[p],p,tp);
for(int i=fir[p];i;i=l[i])if(to[i]!=fa&&to[i]!=hson[p])DFS(to[i],p,to[i]);
}
int lca(int a,int b){
while(top[a]!=top[b])if(dep[top[a]]>dep[top[b]])a=f[top[a]];else b=f[top[b]];
return dep[a]<dep[b]?a:b;
}
int upd(int p,int anc,int r,int rp){
while(top[p]!=top[anc])ans=min(ans,min(rp-ref[pre_ask(rt[dfn[top[p]]-],rt[dfn[p]],r-,,numcnt)],ref[suc_ask(rt[dfn[top[p]]-],rt[dfn[p]],r,,numcnt)]-rp)),p=f[top[p]];
ans=min(ans,min(rp-ref[pre_ask(rt[dfn[anc]-],rt[dfn[p]],r-,,numcnt)],ref[suc_ask(rt[dfn[anc]-],rt[dfn[p]],r,,numcnt)]-rp));
}
main(){//freopen("e2.in","r",stdin);freopen("my.out","w",stdout);
n=read();q=read();type=read();
for(int i=;i<=n;++i)x[i]=a[i]=read();
for(int i=,xx,y;i<n;++i)xx=read(),y=read(),link(xx,y),link(y,xx);
sort(x+,x++n);int P=unique(x+,x++n)-x-;
for(int i=;i<=P;++i)M[x[i]]=++numcnt,ref[numcnt]=x[i];
numcnt++;ref[numcnt]=inf;M[inf]=numcnt;
numcnt++;ref[numcnt]=inf<<;M[inf<<]=numcnt;
ref[]=-inf;
for(int i=;i<=n;++i)a[i]=M[a[i]];
dfs(,);DFS(,,);build();
while(q--){
r=read();k=read();int R=M[*lower_bound(ref+,ref++numcnt,r)];
for(int i=;i<=k;++i)res[i]=(read()-+ans*type)%n+;
int LCA=res[];
for(int i=;i<=k;++i)LCA=lca(LCA,res[i]);
ans=;
for(int i=;i<=k;++i)upd(res[i],LCA,R,r);
printf("%d\n",ans);
}
}

T3:f

挺好的题,也没有想象中那么难。

首先注意最大逆序对数是100000*99999/2=4999950000,所以会炸int。调半天。。。

和之前《比赛》那道题比较像,异或上[0,2k)上的每一个值的话那么两个数会在最高的不相同位分离。

建出trie,这样我们就能求出在每一位上分离的贡献了。

这样的话其实每一位的贡献都是独立的,可以分别考虑。

最暴力的思路就是直接枚举2k个所有数然后nth_element什么的。

 #include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
int a[],n,k,p,k1,k2,rt;long long ctb[][];
int c[][],w[],cnt;
struct Pair{
int id;long long w;
friend bool operator<(Pair a,Pair b){
return a.w<b.w||(a.w==b.w&&a.id<b.id);
}
}p1[],p2[];
void insert(int &p,int v,int al){
if(!p)p=++cnt;w[p]++;
if(al==-)return;
insert(c[p][v&<<al?:],v,al-);
ctb[al][v&<<al?:]+=w[c[p][v&<<al?:]];
}
int chk(Pair x){
long long lower=;
for(int i=;i<<<k1;++i)lower+=lower_bound(p2,p2+(<<k2),(Pair){x.w-p1[i].w,x.id-(p1[i].id<<k2)})-p2;cerr<<lower<<endl;
return lower;
}
int main(){//freopen("f3.in","r",stdin);
n=read(),k=read(),p=read();k1=k>>;k2=k-k1;
for(int i=;i<=n;++i)insert(rt,read(),k-);
for(int i=;i<<<k;++i)p1[i].id=i;
for(int i=;i<<<k;++i)for(int j=;j<k;++j)p1[i].w+=ctb[j][i&<<j?:];
nth_element(p1,p1+p-,p1+(<<k));printf("%lld %d\n",p1[p-].w,p1[p-].id);
}

55分

对于最大的数据范围k=30,我们要采用那种$meet$  $in$  $middle$的思想。

因为每一位的贡献独立,所以其实可以分开考虑前15位与后15位的贡献。

spj已经给出了提示:第一问好做。

因为回答对任意一问可以得到60%的分,而按照我们已有的结论如果知道第二问的话可以$O(k)$求出第一问。

所以关键就在于怎么求出第一问。

值域可以二分答案,关键就在于如何check。

我们可以暴力扫前15位的全部情况,现在的问题就是求出有多少个后15位与它相加小于二分值。

那么我们只需要把第二维排序,然后lower_bound即可。(也可以双指针扫描,少一个log)

这样的话我们就check出了第一问。

 #include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
int a[],n,k,p,k1,k2,rt;long long ctb[][],w[];
int c[][],cnt;
struct Pair{
long long w;int id;
friend bool operator<(Pair a,Pair b){
return a.w<b.w||(a.w==b.w&&a.id<b.id);
}
}p1[],p2[];
void insert(int &p,int v,int al){
if(!p)p=++cnt;w[p]++;
if(al==-)return;
insert(c[p][v&<<al?:],v,al-);
ctb[al][v&<<al?:]+=w[c[p][v&<<al?:]];
}
int chk(Pair x){
long long lower=;
for(int i=;i<<<k1;++i)lower+=upper_bound(p2,p2+(<<k2),(Pair){x.w-p1[i].w,x.id-(p1[i].id<<k2)})-p2;cerr<<lower<<endl;
return lower;
}
int main(){//freopen("f1.in","r",stdin);
n=read(),k=read(),p=read();k1=k>>;k2=k-k1;
for(int i=;i<=n;++i)insert(rt,read(),k-);
for(int i=;i<<<k1;++i)for(int j=;j<k1;++j)p1[i].w+=ctb[j+k2][i&<<j?:];
for(int i=;i<<<k1;++i)p1[i].id=i;
for(int i=;i<<<k2;++i)for(int j=;j<k2;++j)p2[i].w+=ctb[j][i&<<j?:];
for(int i=;i<<<k2;++i)p2[i].id=i;
sort(p1,p1+(<<k1));sort(p2,p2+(<<k2));
long long l=,r=1ll*n*(n-)>>,ans;
while(l<=r)if(chk((Pair){l+r>>,})<p)l=(ans=l+r>>)+;else r=(l+r>>)-;
printf("%lld 0\n",ans);
}

60分

然后确定第一问后,第二问其实是完全一样的,再次二分。

前15位与后15位的二元组运算是$(a,b)+(x,y)=(a+x,(b<<k/2)+y)$

从含义上就能解释,只不过是把劈成两半的二进制数合并。

然后就一模一样的check就可以了。

 #include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int read(){
register int p=;register char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')p=(p<<)+(p<<)+ch-,ch=getchar();
return p;
}
int a[],n,k,p,k1,k2,rt;long long ctb[][],w[];
int c[][],cnt;
struct Pair{
long long w;int id;
friend bool operator<(Pair a,Pair b){
return a.w<b.w||(a.w==b.w&&a.id<b.id);
}
}p1[],p2[];
void insert(int &p,int v,int al){
if(!p)p=++cnt;w[p]++;
if(al==-)return;
insert(c[p][v&<<al?:],v,al-);
ctb[al][v&<<al?:]+=w[c[p][v&<<al?:]];
}
int chk(Pair x){
long long lower=;
for(int i=;i<<<k1;++i)lower+=upper_bound(p2,p2+(<<k2),(Pair){x.w-p1[i].w,x.id-(p1[i].id<<k2)})-p2;cerr<<lower<<endl;
return lower;
}
int main(){//freopen("f3.in","r",stdin);
n=read(),k=read(),p=read();k1=k>>;k2=k-k1;
for(int i=;i<=n;++i)insert(rt,read(),k-);
for(int i=;i<<<k1;++i)for(int j=;j<k1;++j)p1[i].w+=ctb[j+k2][i&<<j?:];
for(int i=;i<<<k1;++i)p1[i].id=i;
for(int i=;i<<<k2;++i)for(int j=;j<k2;++j)p2[i].w+=ctb[j][i&<<j?:];
for(int i=;i<<<k2;++i)p2[i].id=i;
sort(p1,p1+(<<k1));sort(p2,p2+(<<k2));
long long l=,r=1ll*n*(n-)>>,ans,ans2;
while(l<=r)if(chk((Pair){l+r>>,})<p)l=(ans=l+r>>)+;else r=(l+r>>)-;
l=,r=(<<k)-;
while(l<=r)if(chk((Pair){ans,l+r>>})<p)l=(l+r>>)+;else r=(ans2=l+r>>)-;
printf("%lld %lld\n",ans,k?ans2:);
}

99分

然而第一个子任务挂了,不知道为什么。我判掉了。。。怪没脸的。。。

[考试反思]1011csp-s模拟测试68:守恒的更多相关文章

  1. [考试反思]0718 NOIP模拟测试5

    最后一个是我...rank#11 rank#1和rank#2被外校大佬包揽了. 啊...考的太烂说话底气不足... 我考场上在干些什么啊!!! 20分钟“切”掉T2,又27分钟“切”掉T1 切什么切, ...

  2. [考试反思]0814NOIP模拟测试21

    前两名是外校的240.220.kx和skyh拿到了190的[暴力打满]的好成绩. 我第5是170分,然而160分就是第19了. 在前一晚上刚刚爆炸完毕后,心态格外平稳. 想想前一天晚上的挣扎: 啊啊啊 ...

  3. [考试反思]1109csp-s模拟测试106:撞词

    (撞哈希了用了模拟测试28的词,所以这次就叫撞词吧) 蓝色的0... 蓝色的0... 都该联赛了还能CE呢... 考试结束前15分钟左右,期望得分300 然后对拍发现T2伪了写了一个能拿90分的垃圾随 ...

  4. [考试反思]0909csp-s模拟测试41:反典

    说在前面:我是反面典型!!!不要学我!!! 说在前面:向rank1某脸学习,不管是什么题都在考试反思后面稍微写一下题解. 这次是真的真的运气好... 这次知识点上还可以,但是答题策略出了问题... 幸 ...

  5. [考试反思]0729NOIP模拟测试10

    安度因:哇哦. 安度因:谢谢你. 第三个rank1不知为什么就来了.迷之二连?也不知道哪里来的rp 连续两次考试数学都占了比较大的比重,所以我非常幸运的得以发挥我的优势(也许是优势吧,反正数学里基本没 ...

  6. [考试反思]0714/0716,NOIP模拟测试3/4

    这几天时间比较紧啊(其实只是我效率有点低我在考虑要不要坐到后面去吹空调) 但是不管怎么说,考试反思还是要写的吧. 第三次考试反思没写总感觉缺了点什么,但是题都刷不完... 一进图论看他们刷题好快啊为什 ...

  7. [考试反思]1003csp-s模拟测试58:沉淀

    稳住阵脚. 还可以. 至少想拿到的分都拿到了,最后一题的确因为不会按秩合并和线段树分治而想不出来. 对拍了,暴力都拍了.挺稳的. 但是其实也有波折,险些被卡内存. 如果内存使用不连续或申请的内存全部使 ...

  8. [考试反思]0816NOIP模拟测试23

    210 210 210 170 还可以.暴力打满就rk4了? 但不管怎么说,总算是在改完题之后理直气壮的写考试反思了. T1是个dp,说水也不太水.(当然某脸只要A掉了一道题就要说那是水题) 我的思路 ...

  9. [考试反思]0801NOIP模拟测试11

    8月开门红. 放假回来果然像是神志不清一样. 但还是要接受这个事实. 嗯,说好听点,并列rank#7. 说难听点,垃圾rank#18. 都不用粘人名就知道我是哪一个吧... 因为图片不能太长,所以就不 ...

随机推荐

  1. 一文搞定 SonarQube 接入 C#(.NET) 代码质量分析

    1. 前言 C#语言接入Sonar代码静态扫描相较于Java.Python来说,相对麻烦一些.Sonar检测C#代码时需要预先编译,而且C#代码必须用MSbuid进行编译,如果需要使用SonarQub ...

  2. Open Source v.s. Open Core

    摘要 本文翻译自 CMSWire 网站的<Open Source vs. Open Core: What's the Difference?>,主要介绍 Open Source 和 Ope ...

  3. git远程分支不显示问题解决

    因为项目太大,然后直接git clone拉不下来代码 会报error: RPC failed; HTTP 504 curl 22 The requested URL returned error: 5 ...

  4. BUUCTF刷题记录(Web方面)

    WarmUp 首先查看源码,发现有source.php,跟进看看,发现了一堆代码 这个原本是phpmyadmin任意文件包含漏洞,这里面只不过是换汤不换药. 有兴趣的可以看一下之前我做的分析,http ...

  5. Spring Boot (十四): 响应式编程以及 Spring Boot Webflux 快速入门

    1. 什么是响应式编程 在计算机中,响应式编程或反应式编程(英语:Reactive programming)是一种面向数据流和变化传播的编程范式.这意味着可以在编程语言中很方便地表达静态或动态的数据流 ...

  6. Java容器总结

    容器总结 Java容器工具包框架图 List,Set,Map三者的区别 List(对付顺序的好帮手): List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的对象 Set(注重独一无二的性 ...

  7. bugku web8

    打开网站,是一段PHP代码, <?php extract($_GET); if (!empty($ac)) { $f = trim(file_get_contents($fn)); if ($a ...

  8. js仓库。。。

    <script type="text/javascript" src="//ra.revolvermaps.com/0/0/8.js?i=0ln1fndtptz&a ...

  9. 动态分配内存-realloc

    动态分配内存---relloc 关于 malloc 就不多说了,现在看看 realloc: 函数声明: void *realloc(void *ptr, size_t size); 功能:动态改变指针 ...

  10. 渗透测试-基于白名单执行payload--Msiexec

    复现亮神课程  基于白名单执行payload--Msiexec 0x01 关于msiexec Msiexec 是 Windows Installer 的一部分.用于安装 Windows Install ...