zoukankan      html  css  js  c++  java
  • [考试反思]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分

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

  • 相关阅读:
    1-Java基础回顾整理_06_数组
    1-Java基础回顾整理_05_方法
    1-Java基础回顾整理_04_交互、循环、关键字
    1-Java基础回顾整理_03_类型、变量、运算符
    1-Java基础回顾整理_02_java介绍
    1-Java基础回顾整理_01_计算机发展史
    整合SSM
    Spring整合Mybatis--xml配置文件方式
    java设计模式之动态代理
    Mybatis之动态sql
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/11655940.html
Copyright © 2011-2022 走看看