[考试反思]1011csp-s模拟测试68:守恒

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

不出所料,这场稍炸

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

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

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

的确是个菜鸡

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

晚上加油

1012upd:RP守恒,breaked

下一篇反思再说。

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

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

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

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

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

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

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

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

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

注意分数与时间的关系。

T1:d

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

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 int read(){
 5     register int p=0;register char ch=getchar();
 6     while(ch<'0'||ch>'9')ch=getchar();
 7     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 8     return p;
 9 }
10 struct rec{int x,y,id;}rx[100005],ry[100005];
11 bool X(rec a,rec b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
12 bool Y(rec a,rec b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}
13 int n,m;long long ans;char ald[100005];
14 long long chk(int x){
15     int res=m-x;long long fy;//printf("%d
",x);
16     for(int i=1;i<=x;++i)ald[rx[i].id]=1;
17     for(int i=1;i<=n;++i)if(!ald[ry[i].id]&&!res){fy=ry[i].y;break;}else if(!ald[ry[i].id])res--;
18     for(int i=1;i<=x;++i)ald[rx[i].id]=0;//printf("%lld
",fy);
19     if(rx[x+1].x*fy>ans)ans=rx[x+1].x*fy;return rx[x+1].x*fy;
20 }
21 int main(){//freopen("d2.in","r",stdin);freopen("my.out","w",stdout);
22     int t=read();
23     while(t--){
24         n=read(),m=read();
25         for(int i=1;i<=n;++i)rx[i].x=read(),rx[i].y=read(),rx[i].id=i,ry[i]=rx[i];
26         sort(rx+1,rx+1+n,X);sort(ry+1,ry+1+n,Y);
27         int l=0,r=m;ans=0;
28         if(n-1==m){
29             for(int i=1;i<=n;++i)if(1ll*rx[i].x*rx[i].y>ans)ans=1ll*rx[i].x*rx[i].y;
30             goto A;
31         }
32         if(rx[1].x==rx[n].x){ans=1ll*ry[m+1].y*rx[1].x;goto A;}
33         while(l<r-500){
34             long long ansl=chk(l+r>>1),ansr=chk((l+r>>1)+1);
35             if(ansl<ansr)l=l+r>>1;
36             else if(ansr<ansl)r=(l+r>>1)+1;
37             else{break;
38                 ansl=chk(l+(r-l)/3),ansr=chk(l+(r-l)*2/3);
39                 if(ansl<ansr)l=l+(r-l)/3;
40                 else if(ansr>ansl)r=l+(r-l)*2/3;
41                 else break;
42             }
43         }
44         for(;l<=r;++l)chk(l);
45 A:        printf("%lld
",ans);
46     }
47 }
有一点用的乱搞81分

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

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

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

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

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

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

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<queue>
 4 using namespace std;
 5 int read(){
 6     register int p=0;register char ch=getchar();
 7     while(ch<'0'||ch>'9')ch=getchar();
 8     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 9     return p;
10 }
11 struct rec{
12     int x,y;
13     friend bool operator<(rec a,rec b){
14         return a.y>b.y;
15     }
16 }rx[100005];
17 priority_queue<rec>q;
18 bool X(rec a,rec b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
19 int n,m;long long ans;
20 int main(){//freopen("d2.in","r",stdin);freopen("my.out","w",stdout);
21     int t=read();
22     while(t--){
23         n=read(),m=read();ans=0;while(!q.empty())q.pop();
24         for(int i=1;i<=n;++i)rx[i].x=read(),rx[i].y=read();
25         sort(rx+1,rx+1+n,X);
26         for(int i=m+1;i<=n;++i)q.push(rx[i]);
27         for(int i=m;~i;--i)ans=max(ans,1ll*rx[i+1].x*q.top().y),q.push(rx[i]),q.pop();
28         printf("%lld
",ans);
29     }
30 }
View Code

思路积累:

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

T2:e

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

  1 //subtask1-2:violence
  2 //subtask3:ans=|a-r|
  3 //subtask4:ans=|ap-r|
  4 //subtask5:tree*10
  5 //subtask6:min-1
  6 //subtask7-8:2B_balanced_tree?
  7 //subtask9:return 0
  8 //subtask10:2B_balanced_tree?
  9 #include<cstdio>
 10 #include<iostream>
 11 #include<vector>
 12 using namespace std;
 13 int read(){
 14     register int p=0;register char ch=getchar();
 15     while(ch<'0'||ch>'9')ch=getchar();
 16     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 17     return p;
 18 }
 19 int n,q,type,fir[100005],l[200005],to[200005],cnt,a[100005],r[300005],k[300005];
 20 vector<int>v[300005];
 21 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;}
 22 int _abs(int x){return x>0?x:-x;}
 23 int dep[100005],f[100005][20],ap[100005][20][11],mn[100005][20];
 24 int mxk=0,mxr=0,mxa=0,mna=1234567890;
 25 void dfs(int p,int fa){
 26     dep[p]=dep[fa]+1;f[p][0]=fa;if(mxa<=10)ap[p][0][a[p]]=1;mn[p][0]=a[p];
 27     for(int i=1;i<=17;++i){
 28         f[p][i]=f[f[p][i-1]][i-1];mn[p][i]=min(mn[p][i],mn[f[p][i-1]][i-1]);
 29         if(mxa<=10)for(int j=1;j<=10;++j)ap[p][i][j]=ap[p][i-1][j]|ap[f[p][i-1]][i-1][j];
 30     }
 31     for(int i=fir[p];i;i=l[i])if(to[i]!=fa)dfs(to[i],p);
 32 }
 33 int lca(int a,int b){
 34     int sub=dep[a]-dep[b];
 35     if(sub<0)sub=-sub,a^=b^=a^=b;
 36     for(int i=17;~i;--i)if(sub&1<<i)a=f[a][i];//printf("%d %d
",dep[a],dep[b]);
 37     if(a==b)return a;
 38     for(int i=17;~i;--i)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];//,printf("in lca:%d %d %d %d
",a,b,f[a][0],f[b][0]);
 39     return f[a][0];
 40 }
 41 namespace subtask1_2_7_8_10{
 42     int ald[100005];
 43     void main(){
 44         for(int i=1;i<=q;++i){
 45             int LCA=v[i][0],ans=1234567890;
 46             for(int j=1;j<k[i];++j)LCA=lca(LCA,v[i][j]);//,printf("LCA:%d
",LCA);
 47             for(int j=0;j<k[i];++j){
 48                 int p=v[i][j];
 49                 while(ald[p]!=i&&p!=LCA)ans=min(ans,_abs(a[p]-r[i])),ald[p]=i,p=f[p][0];//,printf("%d
",p);
 50             }
 51             printf("%d
",min(ans,_abs(a[LCA]-r[i])));
 52         }
 53     }
 54 }
 55 namespace subtask3{
 56     void main(){
 57         for(int i=1;i<=q;++i)printf("%d
",_abs(a[1]-r[i]));
 58     }
 59 }
 60 namespace subtask4{
 61     void main(){
 62         for(int i=1;i<=q;++i)printf("%d
",_abs(a[v[i][0]]-r[i]));
 63     }
 64 }
 65 namespace subtask5{
 66     void main(){
 67         int alp[11];
 68         for(int i=1;i<=q;++i){
 69             int LCA=v[i][0],ans=11;
 70             for(int j=1;j<k[i];++j)LCA=lca(LCA,v[i][j]);
 71             for(int j=0;j<k[i];++j){
 72                 int sub=dep[v[i][j]]-dep[LCA]+1,p=v[i][j];
 73                 for(int i=17;~i;--i)if(sub&1<<i){
 74                     for(int j=1;j<=10;++j)if(ap[p][i][j])alp[j]=i;
 75                     p=f[p][i];
 76                 }
 77             }
 78             for(int j=1;j<=10;++j)if(alp[j]==i)ans=min(ans,_abs(r[i]-j));
 79             printf("%d
",ans);
 80         }
 81     }
 82 }
 83 namespace subtask6{
 84     void main(){
 85         for(int i=1;i<=q;++i){
 86             int LCA=v[i][0],ans=1234567890;
 87             for(int j=1;j<k[i];++j)LCA=lca(LCA,v[i][j]);
 88             for(int j=0;j<k[i];++j){
 89                 int sub=dep[v[i][j]]-dep[LCA]+1,p=v[i][j];
 90                 for(int i=17;~i;--i)if(sub&1<<i)ans=min(ans,mn[p][i]-1),p=f[p][i];
 91             }
 92             printf("%d
",ans);
 93         }
 94     }
 95 }
 96 namespace subtask9{
 97     void main(){
 98         return;
 99     }
100 }
101 int main(){//freopen("e2.in","r",stdin);freopen("my.out","w",stdout);
102     n=read();q=read();type=read();
103     for(int i=1;i<=n;++i)mxa=max(mxa,a[i]=read()),mna=min(mna,a[i]);
104     for(int i=1,x,y;i<n;++i)x=read(),y=read(),link(x,y),link(y,x);
105     for(int i=1;i<=q;++i){
106         mxr=max(mxr,r[i]=read());mxk=max(mxk,k[i]=read());
107         for(int j=1;j<=k[i];++j)v[i].push_back(read());
108     }
109     dfs(1,0);
110     if(n<=1000)subtask1_2_7_8_10::main();
111     else if(mxa==mxa)subtask3::main();
112     else if(mxk==1)subtask4::main();
113     else if(mxa<=10&&mxr<=10)subtask5::main();
114     else if(mxr==1)subtask6::main();
115     else if(q==0)subtask9::main();
116     else subtask1_2_7_8_10::main();
117 }
View Code

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

第一反应:平衡树上树。

第二反应:主席树上树。

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

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

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

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

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

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 #define inf 1000000000
 5 int read(){
 6     register int p=0;register char ch=getchar();
 7     while(ch<'0'||ch>'9')ch=getchar();
 8     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 9     return p;
10 }
11 int n,q,ans,type,a[100005],res[300005],r,k;
12 int fir[100005],l[200005],to[200005],cnt,f[100005];
13 int w[10000005],pc,rt[100005],lc[10000005],rc[10000005];
14 int siz[100005],hson[100005],top[100005],dfn[100005];
15 int re[100005],dep[100005],tim;
16 void link(int x,int y){l[++cnt]=fir[x];fir[x]=cnt;to[cnt]=y;}
17 //主席树
18 void insert(int &p,int cpy,int l,int r,int v){
19     p=++pc;w[p]=w[cpy]+1;
20     if(l==r)return;
21     if(v<=l+r>>1)insert(lc[p],lc[cpy],l,l+r>>1,v),rc[p]=rc[cpy];
22     else insert(rc[p],rc[cpy],(l+r>>1)+1,r,v),lc[p]=lc[cpy];
23 }
24 void build(){for(int i=1;i<=n;++i)insert(rt[i],rt[i-1],1,inf,a[re[i]]);}
25 int pre_ask(int pl,int pr,int pos,int l,int r){
26     if(w[pr]==w[pl])return -inf;
27     if(l==r)return l;
28     if((l+r>>1)+1<=pos){int x=pre_ask(rc[pl],rc[pr],pos,(l+r>>1)+1,r);if(x!=-inf)return x;}
29     return pre_ask(lc[pl],lc[pr],pos,l,l+r>>1);
30 }
31 int suc_ask(int pl,int pr,int pos,int l,int r){
32     if(w[pr]==w[pl])return inf*2;
33     if(l==r)return l;
34     if(pos<=l+r>>1){int x=suc_ask(lc[pl],lc[pr],pos,l,l+r>>1);if(x!=inf*2)return x;}
35     return suc_ask(rc[pl],rc[pr],pos,(l+r>>1)+1,r);
36 }
37 //树链剖分
38 void dfs(int p,int fa){
39     siz[p]=1;dep[p]=dep[fa]+1;f[p]=fa;
40     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
41         dfs(to[i],p);
42         siz[p]+=siz[to[i]];
43         if(siz[to[i]]>siz[hson[p]])hson[p]=to[i];
44     }
45 }
46 void DFS(int p,int fa,int tp){//printf("dfn:%d
",p);
47     dfn[p]=++tim;top[p]=tp;re[tim]=p;
48     if(hson[p])DFS(hson[p],p,tp);
49     for(int i=fir[p];i;i=l[i])if(to[i]!=fa&&to[i]!=hson[p])DFS(to[i],p,to[i]);
50 }
51 int lca(int a,int b){
52     while(top[a]!=top[b])if(dep[top[a]]>dep[top[b]])a=f[top[a]];else b=f[top[b]];
53     return dep[a]<dep[b]?a:b;
54 }
55 int upd(int p,int anc,int r){
56     while(top[p]!=top[anc])ans=min(ans,min(r-pre_ask(rt[dfn[top[p]]-1],rt[dfn[p]],r,1,inf),suc_ask(rt[dfn[top[p]]-1],rt[dfn[p]],r,1,inf)-r)),p=f[top[p]];
57     ans=min(ans,min(r-pre_ask(rt[dfn[anc]-1],rt[dfn[p]],r,1,inf),suc_ask(rt[dfn[anc]-1],rt[dfn[p]],r,1,inf)-r));
58 }
59 int main(){//freopen("e2.in","r",stdin);freopen("my.out","w",stdout);
60     n=read();q=read();type=read();
61     for(int i=1;i<=n;++i)a[i]=read();
62     for(int i=1,x,y;i<n;++i)x=read(),y=read(),link(x,y),link(y,x);
63     dfs(1,0);DFS(1,0,1);build();
64     while(q--){
65         r=read();k=read();
66         for(int i=1;i<=k;++i)res[i]=(read()-1+ans*type)%n+1;
67         int LCA=res[1];
68         for(int i=2;i<=k;++i)LCA=lca(LCA,res[i]);//cout<<"LCA:"<<LCA<<endl;
69         ans=1234567890;
70         for(int i=1;i<=k;++i)upd(res[i],LCA,r);//,printf("%d
",ans);
71         printf("%d
",ans);
72     }
73 }
TLE89

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

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

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

细节比较多。

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

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

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<map>
 5 using namespace std;
 6 #define inf 1000000000
 7 #define S 100000
 8 int read(){
 9     register int p=0;register char ch=getchar();
10     while(ch<'0'||ch>'9')ch=getchar();
11     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
12     return p;
13 }
14 int n,q,ans,type,a[100005],res[300005],r,k;
15 int fir[100005],l[200005],to[200005],cnt,f[100005];
16 int w[10000005],pc,rt[100005],lc[10000005],rc[10000005];
17 int siz[100005],hson[100005],top[100005],dfn[100005];
18 int re[100005],dep[100005],tim;
19 int x[100005],numcnt,ref[100005];
20 map<int,int>M;
21 void link(int x,int y){l[++cnt]=fir[x];fir[x]=cnt;to[cnt]=y;}
22 //主席树
23 void insert(int &p,int cpy,int l,int r,int v){
24     p=++pc;w[p]=w[cpy]+1;
25     if(l==r)return;
26     if(v<=l+r>>1)insert(lc[p],lc[cpy],l,l+r>>1,v),rc[p]=rc[cpy];
27     else insert(rc[p],rc[cpy],(l+r>>1)+1,r,v),lc[p]=lc[cpy];
28 }
29 void build(){for(int i=1;i<=n;++i)insert(rt[i],rt[i-1],0,numcnt,a[re[i]]);}
30 int pre_ask(int pl,int pr,int pos,int l,int r){
31     if(w[pr]==w[pl])return 0;
32     if(l==r)return l;
33     if((l+r>>1)+1<=pos){int x=pre_ask(rc[pl],rc[pr],pos,(l+r>>1)+1,r);if(x)return x;}
34     return pre_ask(lc[pl],lc[pr],pos,l,l+r>>1);
35 }
36 int suc_ask(int pl,int pr,int pos,int l,int r){
37     if(w[pr]==w[pl])return numcnt;
38     if(l==r)return l;
39     if(pos<=l+r>>1){int x=suc_ask(lc[pl],lc[pr],pos,l,l+r>>1);if(x!=numcnt)return x;}
40     return suc_ask(rc[pl],rc[pr],pos,(l+r>>1)+1,r);
41 }
42 //树链剖分
43 void dfs(int p,int fa){
44     siz[p]=1;dep[p]=dep[fa]+1;f[p]=fa;
45     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
46         dfs(to[i],p);
47         siz[p]+=siz[to[i]];
48         if(siz[to[i]]>siz[hson[p]])hson[p]=to[i];
49     }
50 }
51 void DFS(int p,int fa,int tp){//printf("dfn:%d
",p);
52     dfn[p]=++tim;top[p]=tp;re[tim]=p;
53     if(hson[p])DFS(hson[p],p,tp);
54     for(int i=fir[p];i;i=l[i])if(to[i]!=fa&&to[i]!=hson[p])DFS(to[i],p,to[i]);
55 }
56 int lca(int a,int b){
57     while(top[a]!=top[b])if(dep[top[a]]>dep[top[b]])a=f[top[a]];else b=f[top[b]];
58     return dep[a]<dep[b]?a:b;
59 }
60 int upd(int p,int anc,int r,int rp){
61     while(top[p]!=top[anc])ans=min(ans,min(rp-ref[pre_ask(rt[dfn[top[p]]-1],rt[dfn[p]],r-1,0,numcnt)],ref[suc_ask(rt[dfn[top[p]]-1],rt[dfn[p]],r,0,numcnt)]-rp)),p=f[top[p]];
62     ans=min(ans,min(rp-ref[pre_ask(rt[dfn[anc]-1],rt[dfn[p]],r-1,0,numcnt)],ref[suc_ask(rt[dfn[anc]-1],rt[dfn[p]],r,0,numcnt)]-rp));
63 }
64 main(){//freopen("e2.in","r",stdin);freopen("my.out","w",stdout);
65     n=read();q=read();type=read();
66     for(int i=1;i<=n;++i)x[i]=a[i]=read();
67     for(int i=1,xx,y;i<n;++i)xx=read(),y=read(),link(xx,y),link(y,xx);
68     sort(x+1,x+1+n);int P=unique(x+1,x+1+n)-x-1;
69     for(int i=1;i<=P;++i)M[x[i]]=++numcnt,ref[numcnt]=x[i];
70     numcnt++;ref[numcnt]=inf;M[inf]=numcnt;
71     numcnt++;ref[numcnt]=inf<<1;M[inf<<1]=numcnt;
72     ref[0]=-inf;
73     for(int i=1;i<=n;++i)a[i]=M[a[i]];
74     dfs(1,0);DFS(1,0,1);build();
75     while(q--){
76         r=read();k=read();int R=M[*lower_bound(ref+1,ref+1+numcnt,r)];
77         for(int i=1;i<=k;++i)res[i]=(read()-1+ans*type)%n+1;
78         int LCA=res[1];
79         for(int i=2;i<=k;++i)LCA=lca(LCA,res[i]);
80         ans=1234567890;
81         for(int i=1;i<=k;++i)upd(res[i],LCA,R,r);
82         printf("%d
",ans);
83     }
84 }
View Code

T3:f

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

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

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

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

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

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

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 int read(){
 6     register int p=0;register char ch=getchar();
 7     while(ch<'0'||ch>'9')ch=getchar();
 8     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 9     return p;
10 }
11 int a[100005],n,k,p,k1,k2,rt;long long ctb[31][2];
12 int c[3000005][2],w[3000005],cnt;
13 struct Pair{
14     int id;long long w;
15     friend bool operator<(Pair a,Pair b){
16         return a.w<b.w||(a.w==b.w&&a.id<b.id);
17     }
18 }p1[1048576],p2[32769];
19 void insert(int &p,int v,int al){
20     if(!p)p=++cnt;w[p]++;
21     if(al==-1)return;
22     insert(c[p][v&1<<al?1:0],v,al-1);
23     ctb[al][v&1<<al?1:0]+=w[c[p][v&1<<al?0:1]];
24 }
25 int chk(Pair x){
26     long long lower=0;
27     for(int i=0;i<1<<k1;++i)lower+=lower_bound(p2,p2+(1<<k2),(Pair){x.w-p1[i].w,x.id-(p1[i].id<<k2)})-p2;cerr<<lower<<endl;
28     return lower;
29 }
30 int main(){//freopen("f3.in","r",stdin);
31     n=read(),k=read(),p=read();k1=k>>1;k2=k-k1;
32     for(int i=1;i<=n;++i)insert(rt,read(),k-1);
33     for(int i=0;i<1<<k;++i)p1[i].id=i;
34     for(int i=0;i<1<<k;++i)for(int j=0;j<k;++j)p1[i].w+=ctb[j][i&1<<j?1:0];
35     nth_element(p1,p1+p-1,p1+(1<<k));printf("%lld %d
",p1[p-1].w,p1[p-1].id);
36 }
55分

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

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

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

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

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

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

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

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

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

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 int read(){
 6     register int p=0;register char ch=getchar();
 7     while(ch<'0'||ch>'9')ch=getchar();
 8     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 9     return p;
10 }
11 int a[500005],n,k,p,k1,k2,rt;long long ctb[31][2],w[15000005];
12 int c[15000005][2],cnt;
13 struct Pair{
14     long long w;int id;
15     friend bool operator<(Pair a,Pair b){
16         return a.w<b.w||(a.w==b.w&&a.id<b.id);
17     }
18 }p1[32769],p2[32769];
19 void insert(int &p,int v,int al){
20     if(!p)p=++cnt;w[p]++;
21     if(al==-1)return;
22     insert(c[p][v&1<<al?1:0],v,al-1);
23     ctb[al][v&1<<al?1:0]+=w[c[p][v&1<<al?0:1]];
24 }
25 int chk(Pair x){
26     long long lower=0;
27     for(int i=0;i<1<<k1;++i)lower+=upper_bound(p2,p2+(1<<k2),(Pair){x.w-p1[i].w,x.id-(p1[i].id<<k2)})-p2;cerr<<lower<<endl;
28     return lower;
29 }
30 int main(){//freopen("f1.in","r",stdin);
31     n=read(),k=read(),p=read();k1=k>>1;k2=k-k1;
32     for(int i=1;i<=n;++i)insert(rt,read(),k-1);
33     for(int i=0;i<1<<k1;++i)for(int j=0;j<k1;++j)p1[i].w+=ctb[j+k2][i&1<<j?1:0];
34     for(int i=0;i<1<<k1;++i)p1[i].id=i;
35     for(int i=0;i<1<<k2;++i)for(int j=0;j<k2;++j)p2[i].w+=ctb[j][i&1<<j?1:0];
36     for(int i=0;i<1<<k2;++i)p2[i].id=i;
37     sort(p1,p1+(1<<k1));sort(p2,p2+(1<<k2));
38     long long l=0,r=1ll*n*(n-1)>>1,ans;
39     while(l<=r)if(chk((Pair){l+r>>1,0})<p)l=(ans=l+r>>1)+1;else r=(l+r>>1)-1;
40     printf("%lld 0
",ans);
41 }
60分

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

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

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

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

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 int read(){
 6     register int p=0;register char ch=getchar();
 7     while(ch<'0'||ch>'9')ch=getchar();
 8     while(ch>='0'&&ch<='9')p=(p<<3)+(p<<1)+ch-48,ch=getchar();
 9     return p;
10 }
11 int a[500005],n,k,p,k1,k2,rt;long long ctb[31][2],w[15000005];
12 int c[15000005][2],cnt;
13 struct Pair{
14     long long w;int id;
15     friend bool operator<(Pair a,Pair b){
16         return a.w<b.w||(a.w==b.w&&a.id<b.id);
17     }
18 }p1[32769],p2[32769];
19 void insert(int &p,int v,int al){
20     if(!p)p=++cnt;w[p]++;
21     if(al==-1)return;
22     insert(c[p][v&1<<al?1:0],v,al-1);
23     ctb[al][v&1<<al?1:0]+=w[c[p][v&1<<al?0:1]];
24 }
25 int chk(Pair x){
26     long long lower=0;
27     for(int i=0;i<1<<k1;++i)lower+=upper_bound(p2,p2+(1<<k2),(Pair){x.w-p1[i].w,x.id-(p1[i].id<<k2)})-p2;cerr<<lower<<endl;
28     return lower;
29 }
30 int main(){//freopen("f3.in","r",stdin);
31     n=read(),k=read(),p=read();k1=k>>1;k2=k-k1;
32     for(int i=1;i<=n;++i)insert(rt,read(),k-1);
33     for(int i=0;i<1<<k1;++i)for(int j=0;j<k1;++j)p1[i].w+=ctb[j+k2][i&1<<j?1:0];
34     for(int i=0;i<1<<k1;++i)p1[i].id=i;
35     for(int i=0;i<1<<k2;++i)for(int j=0;j<k2;++j)p2[i].w+=ctb[j][i&1<<j?1:0];
36     for(int i=0;i<1<<k2;++i)p2[i].id=i;
37     sort(p1,p1+(1<<k1));sort(p2,p2+(1<<k2));
38     long long l=0,r=1ll*n*(n-1)>>1,ans,ans2;
39     while(l<=r)if(chk((Pair){l+r>>1,0})<p)l=(ans=l+r>>1)+1;else r=(l+r>>1)-1;
40     l=0,r=(1<<k)-1;
41     while(l<=r)if(chk((Pair){ans,l+r>>1})<p)l=(l+r>>1)+1;else r=(ans2=l+r>>1)-1;
42     printf("%lld %lld
",ans,k?ans2:0);
43 }
99分

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

原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11655940.html