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

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

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

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

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

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

无话可说,只能

然后是$T3$,这次的强制在线是$x=(x\xor 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)

大意:多次询问求$\min\limits_{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\n",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} \times \frac{n}{L} log\frac{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\n",la=ans+R.cnt());R=Y;
46     }
47 }
View Code

 

posted @ 2020-04-18 20:15  DeepinC  阅读(299)  评论(0编辑  收藏  举报