• [考试反思]0418省选模拟74:杂枝


    好像现在乱搞已经在心里扎根了。

    三道题的暴力分给的都很足,暴力写满大约是$60+60+33=153$。思维难度都不大。

    然而$T2$我是怎么判断这是否为一个菊花的呢?

    除非$n=1$,万物皆菊花。

    然后就只得到了判菊花的$20$,链的$10$和纯暴力的$30$都没了。

    无话可说,只能

    然后是$T3$,这次的强制在线是$x=(xxor lastans)mod n +1$。

    所以那个$+1$就炸掉了。还能有$25$实属不易。

    反正就是极度弱智的一场,写了三个暴力挂了俩,想乱搞一分没多拿。

    而且这次的正解貌似都不算难但是一个都没想(可能都没花多少时间思考。。

    俩结论一分块(虚树什么的还是算了)

    又开始了分数是黄色的时光。。。

    T1:签到

    大意:网格左上出发走到右下,可以重复经过一个点(包括右下),最大化 经过次数为奇数的点 的权值 的异或和。$n,m le 500,w_i le 10^9$

    大约是结论题:只要任意选出的点个数与$n+m-1$奇偶性相同,那么这些点的异或和就是一种合法路径的权值。

    大致理解就是:先随便走一条覆盖了所有点的路径(可覆盖多次),然后对于路径上任意点$A,B$我们可以在经过点$A$时,

    沿任意路径$s$走到$B$后再沿路径$s$折返回$A$。中间所有点都往返共经过了$2$次,只有$A,B$恰好多经过了一次。

    也就是说我们可以任选两个点将其取反。所以结论成立。

    所以问题是:你可以在$nm$个值中任选奇数/偶数个,最大化异或和。

    怎么限制选的个数的奇偶呢?我们把所有数的最高位赋为$1$。这样如果你选了奇数个,最高位就会是$1$否则为$0$

    所以只要根据奇偶最开始查询线性基是否带有最高位的$1$就可以直接做了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 13666663
     4 int n,m,ans,b[32];
     5 void ins(int x){for(int i=30;~i;--i)if(x&1<<i)if(b[i])x^=b[i];else b[i]=x,x=0;}
     6 int main(){
     7     cin>>n>>m;
     8     for(int i=1,x;i<=n*m;++i)scanf("%d",&x),ins(x|1<<30);
     9     ans=(n+m&1)<<30;
    10     for(int i=30;~i;--i)if(!(ans&1<<i))ans^=b[i];
    11     cout<<ans-(1<<30)<<endl;
    12 }
    View Code

    T2:树(tree)

    大意:多次询问求$minlimits_{i=l}^{r} dis(i,x)$。$n,q le 10^5$

    首先正解的做法就是,像线段树一样把询问离线下来撒在$log$个区间上。

    然后对于每个区间,把区间内所有点和询问点一起拿出来建虚树

    写的好的话是$O(n log n)$。

    考虑另一个简单粗暴的分块做法:

    求出$dp[i][j]$表示第$i$块内的所有点到$j$的最小距离。这个可以直接换根$dp$。对于每一个块$O(n)$得到

    然后零散部分暴力查询(预处理,弄个$O(1)lca$就成)

    思路非常简单粗暴。时间复杂度$O(n sqrt{n})$。需要注意常数。代码比较好写。

    一个显而易见的剪枝:先查询整块(更新答案的概率大)如果边缘块的最小值无法更新答案则直接跳出($O(1)lca$常数不小)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 200002
     4 #define L 800
     5 int fir[S>>1],l[S],to[S],w[S],ec,n,q,ST[18][S],dfn[S>>1],tim,dep[S>>1],dp[S/2/L+1][S>>1],B,bit[S];
     6 void link(int a,int b,int v){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;w[ec]=v;}
     7 void pre(int p,int fa){
     8     ST[0][dfn[p]=++tim]=dep[p];
     9     for(int i=0;i<=B;++i)dp[i][p]=0x3fffffff; dp[p/L][p]=0;
    10     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
    11         dep[to[i]]=dep[p]+w[i],pre(to[i],p),ST[0][++tim]=dep[p];
    12         for(int j=0;j<=B;++j)if(dp[j][p])dp[j][p]=min(dp[j][p],dp[j][to[i]]+w[i]);
    13     }
    14 }
    15 int dis(int a,int b){
    16     a=dfn[a];b=dfn[b];if(a>b)swap(a,b); int B=bit[b-a+1];
    17     return -min(ST[B][a],ST[B][b-(1<<B)+1])<<1;
    18 }
    19 void dfs(int p,int fa){
    20     for(int i=fir[p];i;i=l[i])if(to[i]!=fa){
    21         for(int j=0;j<=B;++j)dp[j][to[i]]=min(dp[j][to[i]],dp[j][p]+w[i]);
    22         dfs(to[i],p);
    23     }
    24 }
    25 int in(){int p=0;char ch=getchar();
    26     for(;!isdigit(ch);ch=getchar());for(;isdigit(ch);ch=getchar())p=p*10+ch-48;
    27     return p;
    28 }
    29 int main(){//freopen("game10.in","r",stdin);freopen("0.out","w",stdout);
    30     n=in();
    31     for(int i=1,a,b,v;i<n;++i)a=in()-1,b=in()-1,v=in(),link(a,b,v),link(b,a,v);
    32     B=(n-1)/L; pre(0,-1); dfs(0,-1);// return 0;
    33     for(int i=1;i<18;++i)for(int j=1;j+(1<<i)-1<=tim;++j)ST[i][j]=min(ST[i-1][j],ST[i-1][j+(1<<i-1)]);
    34     for(int i=0;i<18;++i)for(int j=1<<i;j<1<<i+1&&j<=tim;++j)bit[j]=i;
    35     cin>>q; while(q--){
    36         int l=in()-1,r=in()-1,x=in()-1,ans=0x3fffffff;
    37         if(l<=x&&x<=r){puts("0");continue;}
    38         if(l/L==r/L)for(int i=l;i<=r;++i)ans=min(ans,dis(i,x)+dep[i]);
    39         else{
    40             for(int i=l/L+1;i<r/L;++i)ans=min(ans,dp[i][x]-dep[x]);
    41             if(dp[l/L][x]<ans+dep[x])for(int i=l/L*L+L-1;i>=l;--i)ans=min(ans,dis(i,x)+dep[i]);
    42             if(dp[r/L][x]<ans+dep[x])for(int i=r/L*L;i<=r;++i)ans=min(ans,dis(i,x)+dep[i]); r=r/L-1;
    43         }printf("%d
    ",ans+dep[x]);
    44     }
    45 }
    View Code

    T3:区间(interval)

    大意:在线多区间并数颜色。$n ,sum k le 10^5$。空间限制$8MiB$

    数颜色好像一直没什么好的方法,一在线做法就很少了,再卡一下空间主席树就死了。

    好像就剩$O(n^2)$的做法了?那只能$bitset$了啊。

    分块$bitset$看起来很优秀,然而合并代价过大,可能就是$O(n^{2.5})$的了。

    然后听$dkk$大神讲了$Method of 4 Russians$。名字挺神奇的,但是大概意思就是分块+数据结构维护块之间。

    有什么优秀的数据结构,可以快速查询区间或和呢?$ST$表。

    假如我们的块长为$L$,那么我们最终单次询问的复杂度是:

    两侧暴力查询(单点修改$bitset$):$O(L)$

    中间$ST$表区间查询(需要$bitset$或):$O(frac{n}{64})$

    预处理的复杂度是$O(frac{n}{64} imes frac{n}{L} logfrac{n}{L})$

    总空间消耗与预处理的时间复杂度是相同的。

    权衡之下,最优的块长是$frac{n}{64}$。

    所以只要手写个$bitset$就可以过去了。

    也可以优化,把序列中只出现了一次的颜色提出去单独计算,那么剩余的值域范围至少减半。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 100005
     4 int a[S],c[S],n,W,N,L,cb[65536],q,op,fi,la,rb[64],ans;
     5 struct bit{
     6     unsigned long long b[782];
     7     void operator|=(bit&z){for(int i=(N-1>>6)+1;~i;--i)b[i]|=z.b[i];}
     8     int cnt(int a=0){for(int i=(N-1>>6)+1;~i;--i)a+=cb[b[i]&65535]+cb[b[i]>>16&65535]+cb[b[i]>>32&65535]+cb[b[i]>>48&65535];return a;}
     9 }ST[7][64],Y,R;
    10 struct qry{int l,r;friend bool operator<(qry a,qry b){return a.l<b.l;}}Q[S];
    11 void cal(int l,int r){
    12     if(l/L==r/L){for(int i=r;i>=l;--i)if(~a[i])R.b[a[i]>>6]|=1ll<<(a[i]&63);else ans++;}
    13     else{
    14         for(int i=l/L*L+L-1;i>=l;--i)if(~a[i])R.b[a[i]>>6]|=1ll<<(a[i]&63);else ans++;
    15         for(int i=r/L*L;i<=r;++i)if(~a[i])R.b[a[i]>>6]|=1ll<<(a[i]&63);else ans++;
    16         l=l/L+1;r=r/L-1;
    17         if(l<=r){int z=rb[r-l+1];R|=ST[z][l];R|=ST[z][r-(1<<z)+1];}
    18         for(int i=l;i<=r;++i)ans+=c[i];
    19     }
    20 }
    21 int main(){
    22     //freopen("0.in","r",stdin);freopen("3.out","w",stdout);
    23     cin>>n>>q>>op;
    24     for(int i=0;i<n;++i)scanf("%d",&a[i]),c[a[i]]++;
    25     for(int i=0;i<n;++i)if(c[a[i]]==1)a[i]=-1;
    26     for(int i=0;i<n;++i)if(~a[i])c[++N]=a[i];
    27     sort(c+1,c+1+N); N=unique(c+1,c+1+N)-c;
    28     for(int i=0;i<n;++i)if(~a[i])a[i]=lower_bound(c+1,c+N,a[i])-c-1;
    29     L=(n-1>>6)+1;
    30     for(int i=0;i<64;++i)c[i]=0;
    31     for(int i=0;i<64;++i)for(int j=i*L;j<i*L+L&&j<n;++j)if(~a[j])ST[0][i].b[a[j]>>6]|=1ll<<(a[j]&63);else c[i]++;
    32     for(int i=1;i<7;++i)for(int j=0;j+(1<<i)<=64;++j)ST[i][j]=ST[i-1][j],ST[i][j]|=ST[i-1][j+(1<<i-1)];
    33     for(int i=1;i<65536;++i)cb[i]=cb[i^i&-i]+1;
    34     for(int i=0;i<7;++i)for(int j=1<<i;j<1<<i+1&&j<65;++j)rb[j]=i;
    35     for(int _=1;_<=q;++_){
    36         int k;ans=0;scanf("%d",&k);
    37         for(int i=1;i<=k;++i){
    38             int l,r;scanf("%d%d",&l,&r);
    39             if(op&&fi){l=(l^la)%n;r=(r^la)%n;if(l>r)swap(l,r);}else l--,r--;
    40             Q[i]=(qry){l,r};
    41         }
    42         sort(Q+1,Q+1+k);
    43         for(int i=2;i<=k;++i)if(Q[i].l<=Q[i-1].r+1)Q[i].r=max(Q[i-1].r,Q[i].r),Q[i].l=Q[i-1].l;else cal(Q[i-1].l,Q[i-1].r);
    44         cal(Q[k].l,Q[k].r);
    45         fi=1;printf("%d
    ",la=ans+R.cnt());R=Y;
    46     }
    47 }
    View Code
  • 相关阅读:
    VSCode创建自定义代码段
    生命不息,折腾不止 ~ 旧PC改造之家庭影音
    万物互联之~网络编程基础篇
    PyCharm创建自定义代码段(JetBrains系列通用)
    VSCode设置Tab键为4个空格
    Jupyter-Notebook服务器自定义密码
    Jupyter ~ 像写文章般的 Coding (附:同一个ipynb文件,执行多语言代码)
    centos下使用nohup
    在centos中创建nginx启动脚本
    查看centos中的用户和用户组
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12727808.html
Copyright © 2020-2023  润新知