bzoj 4568: [Scoi2016]幸运数字

4568: [Scoi2016]幸运数字

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 848  Solved: 336
[Submit][Status][Discuss]

Description

A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个

幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。一些旅行者希望游览 A 国。旅行者计划

乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国。

在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸

运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。例如,

游览者拍了 3 张照片,幸运值分别是 5,7,11,那么最终保留在自己身上的幸运值就是 9(5 xor 7 xor 11)。

有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 5

和 11 ,可以保留的幸运值为 14 。现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中

可以保留的最大幸运值是多少。

lyd说这道题维护倍增数组后暴力合并就可以。

于是。。。。

我不是有意要卡评测啊啊啊啊

然后发现果然合并有更NB的方法。

不是高斯消元(原谅我zz),而是应该一个一个插。

终于19sA掉了。

52s

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #define ll long long
  6 #define N 20005
  7 using namespace std;
  8 int read()
  9 {
 10     int p=0;char c=getchar();
 11     while(c<‘0‘||c>‘9‘)c=getchar();
 12     while(c>=‘0‘&&c<=‘9‘)p=p*10+c-‘0‘,c=getchar();
 13     return p;
 14 }
 15 int n,m;
 16 int head[N],ver[N*2],nxt[N*2],tot;
 17 ll mi[N];
 18 void add(int a,int b)
 19 {
 20     tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;return ;
 21 }
 22 ll ji[N][16][62];
 23 int fa[N][16],dep[N];
 24 ll a[N];
 25 void dfs(int x,int f)
 26 {
 27     for(int i=head[x];i;i=nxt[i])
 28     {
 29         if(ver[i]==f)continue;
 30         fa[ver[i]][0]=x;
 31         dep[ver[i]]=dep[x]+1;
 32         ji[ver[i]][0][0]=1;
 33         ji[ver[i]][0][1]=a[ver[i]];
 34         dfs(ver[i],x);
 35     }
 36     return ;
 37 }
 38 ll tmp[182];
 39 void guess()
 40 {
 41     int k=1;int now=tmp[0];
 42     for(int i=60;i>=0;i--)
 43     {
 44         int p=0;ll o=mi[i];
 45         for(int j=k;j<=now;j++)
 46         {
 47             if((tmp[j]&o))
 48             {
 49                 p=j;break;
 50             }
 51         }
 52         if(p)
 53         {
 54             swap(tmp[p],tmp[k]);
 55             for(int j=1;j<=now;j++)
 56             {
 57                 if(j!=k&&(tmp[j]&o))
 58                 {
 59                     tmp[j]^=tmp[k];
 60                 }
 61             }k++;
 62         }
 63     }
 64     tmp[0]=k-1;
 65 }
 66 void yu()
 67 {
 68     for(int i=1;i<=15;i++)
 69     {
 70         for(int j=1;j<=n;j++)
 71         {
 72             tmp[0]=ji[j][i-1][0]+ji[fa[j][i-1]][i-1][0];
 73             for(int k=1;k<=ji[j][i-1][0];k++)tmp[k]=ji[j][i-1][k];
 74             for(int k=1;k<=ji[fa[j][i-1]][i-1][0];k++)tmp[k+ji[j][i-1][0]]=ji[fa[j][i-1]][i-1][k];
 75             guess();
 76             for(int k=0;k<=tmp[0];k++)ji[j][i][k]=tmp[k];
 77             fa[j][i]=fa[fa[j][i-1]][i-1];
 78         }
 79     }return ;
 80 }
 81 void solve(int x,int y)
 82 {
 83     if(dep[x]<dep[y])swap(x,y);
 84     for(int i=15;i>=0;i--)
 85     {
 86         if(dep[fa[x][i]]>=dep[y])
 87         {
 88             for(int j=1;j<=ji[x][i][0];j++)tmp[0]++,tmp[tmp[0]]=ji[x][i][j];
 89             guess();
 90             x=fa[x][i];
 91         }
 92     }
 93     if(x!=y)
 94     {
 95         for(int i=15;i>=0;i--)
 96         {
 97             if(fa[x][i]!=fa[y][i])
 98             {
 99                 for(int k=1;k<=ji[x][i][0];k++)tmp[0]++,tmp[tmp[0]]=ji[x][i][k];
100                 guess();
101                 for(int k=1;k<=ji[y][i][0];k++)tmp[0]++,tmp[tmp[0]]=ji[y][i][k];
102                 guess();
103                 x=fa[x][i];y=fa[y][i];
104             }
105         }
106         tmp[0]++;tmp[tmp[0]]=a[fa[x][0]];
107         tmp[0]++;tmp[tmp[0]]=a[x];
108         tmp[0]++;tmp[tmp[0]]=a[y];
109     }
110     else
111     {
112         tmp[0]++,tmp[tmp[0]]=a[x];
113     }
114     guess();
115     ll now=0;
116     for(int i=tmp[0];i>=1;i--)
117     {
118         now^=tmp[i];
119     }
120     printf("%lld\n",now);
121     return ;
122 }
123 int main()
124 {
125     int q;
126     mi[0]=1;
127     for(int i=1;i<=60;i++)mi[i]=mi[i-1]*2;
128     scanf("%d%d",&n,&q);
129     for(int i=1;i<=n;i++)
130     {
131         scanf("%lld",&a[i]);
132     }
133     int t1,t2,t3;
134     for(int i=1;i<n;i++)
135     {
136         t1=read();t2=read();
137         add(t1,t2);add(t2,t1);
138     }
139     dep[1]=1;
140     ji[1][0][0]=1;ji[1][0][1]=a[1];
141     dfs(1,-1);
142     yu();
143     for(int i=1;i<=q;i++)
144     {
145         t1=read();t2=read();
146         memset(tmp,0,sizeof(tmp));
147         solve(t1,t2);
148     }
149     return 0;
150 }

19s

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #define ll long long
  6 #define N 20005
  7 using namespace std;
  8 int read()
  9 {
 10     int p=0;char c=getchar();
 11     while(c<‘0‘||c>‘9‘)c=getchar();
 12     while(c>=‘0‘&&c<=‘9‘)p=p*10+c-‘0‘,c=getchar();
 13     return p;
 14 }
 15 int n,m;
 16 int head[N],ver[N*2],nxt[N*2],tot;
 17 ll mi[N];
 18 void add(int a,int b)
 19 {
 20     tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;return ;
 21 }
 22 ll ji[N][16][62];
 23 int fa[N][16],dep[N];
 24 ll a[N];
 25 void dfs(int x,int f)
 26 {
 27     for(int i=head[x];i;i=nxt[i])
 28     {
 29         if(ver[i]==f)continue;
 30         fa[ver[i]][0]=x;
 31         dep[ver[i]]=dep[x]+1;
 32         for(int j=60;j>=0;j--)
 33         {
 34             if(a[ver[i]]&mi[j])
 35             {
 36                 ji[ver[i]][0][j]=a[ver[i]];
 37                 break;
 38             }
 39         }
 40         dfs(ver[i],x);
 41     }
 42     return ;
 43 }
 44 ll tmp[61];
 45 void insert(ll x)
 46 {
 47     for(int i=60;i>=0;i--)
 48     {
 49         if(x&mi[i])
 50         {
 51             if(!tmp[i])
 52             {
 53                 tmp[i]=x;
 54                 break;
 55             }
 56             else x^=tmp[i];
 57         }
 58     }return ;
 59 }
 60 void yu()
 61 {
 62     for(int i=1;i<=15;i++)
 63     {
 64         for(int j=1;j<=n;j++)
 65         {
 66             for(int k=0;k<=60;k++)tmp[k]=ji[j][i-1][k];
 67             for(int k=0;k<=60;k++)
 68             {
 69                 if(ji[fa[j][i-1]][i-1][k])insert(ji[fa[j][i-1]][i-1][k]);
 70             }
 71             for(int k=0;k<=60;k++)ji[j][i][k]=tmp[k];
 72             fa[j][i]=fa[fa[j][i-1]][i-1];
 73         }
 74     }return ;
 75 }
 76 void solve(int x,int y)
 77 {
 78     if(dep[x]<dep[y])swap(x,y);
 79     for(int i=15;i>=0;i--)
 80     {
 81         if(dep[fa[x][i]]>=dep[y])
 82         {
 83             for(int j=0;j<=60;j++)if(ji[x][i][j])insert(ji[x][i][j]);
 84             x=fa[x][i];
 85         }
 86     }
 87     if(x!=y)
 88     {
 89         for(int i=15;i>=0;i--)
 90         {
 91             if(fa[x][i]!=fa[y][i])
 92             {
 93                 for(int k=0;k<=60;k++)if(ji[x][i][k])insert(ji[x][i][k]);
 94                 for(int k=0;k<=60;k++)if(ji[y][i][k])insert(ji[y][i][k]);
 95                 x=fa[x][i];y=fa[y][i];
 96             }
 97         }
 98         insert(a[fa[x][0]]);insert(a[x]);insert(a[y]);
 99     }
100     else
101     {
102         insert(a[x]);
103     }
104     ll now=0;
105     for(int i=60;i>=0;i--)
106     {
107         now=max(now,now^(tmp[i]));
108     }
109     printf("%lld\n",now);
110     return ;
111 }
112 int main()
113 {
114     int q;
115     mi[0]=1;
116     for(int i=1;i<=60;i++)mi[i]=mi[i-1]*2;
117     scanf("%d%d",&n,&q);
118     for(int i=1;i<=n;i++)
119     {
120         scanf("%lld",&a[i]);
121     }
122     int t1,t2,t3;
123     for(int i=1;i<n;i++)
124     {
125         t1=read();t2=read();
126         add(t1,t2);add(t2,t1);
127     }
128     dep[1]=1;
129     for(int i=60;i>=0;i--)
130     {
131         if(a[1]&mi[i])
132         {
133             ji[1][0][i]=a[1];
134             break;
135         }
136     }
137     dfs(1,-1);
138     yu();
139     for(int i=1;i<=q;i++)
140     {
141         t1=read();t2=read();
142         memset(tmp,0,sizeof(tmp));
143         solve(t1,t2);
144     }
145     return 0;
146 }
时间: 2024-10-10 14:54:30

bzoj 4568: [Scoi2016]幸运数字的相关文章

【BZOJ 4568】 4568: [Scoi2016]幸运数字 (线性基+树链剖分+线段树)

4568: [Scoi2016]幸运数字 Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国. 在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上.然而,幸

[BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2131  Solved: 865[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x

BZOJ4568:[SCOI2016]幸运数字——题解

https://www.lydsy.com/JudgeOnline/problem.php?id=4568 https://www.luogu.org/problemnew/show/P3292 A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征. 一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y

bzoj4568 [Scoi2016]幸运数字

Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国.在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上.然而,幸运是不能简单叠加的,这一点游览者也十分清楚.他们迷

bzoj 1853: [Scoi2010]幸运数字 容斥

1853: [Scoi2010]幸运数字 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 1170  Solved: 406[Submit][Status] Description 在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6,8,66,68,86,

bzoj4568: [Scoi2016]幸运数字 线性基 倍增

洛谷T了,mmp 还是bzoj时限良心,虽然三天两头爆炸 算是简单的题吧,构造出每个点logn个的线性基表 感觉线性基最nb的就是只有log个,所以可以做的很暴力 合并就是拆开再并 1 #include <bits/stdc++.h> 2 using namespace std; 3 struct Bas 4 { 5 long long a[61]; 6 Bas() 7 { 8 for(int i=0;i<=60;i++) 9 a[i]=0; 10 } 11 void add(long

BZOJ 1853 SCOI2010 幸运数字 容斥原理+DFS

题目大意:求[l,r]区间内有多少个数是只由6和8组成的数的倍数 同2393 链接:http://blog.csdn.net/popoqqq/article/details/41807333 此题数据强力了一些 由于r<=10^10 所以计算LCM的时候会爆long long 于是我们可以用double求出LCM的近似值与r进行比较 如果小于r再取精确值进行计算 此外就是搜索的时候要从大到小搜 从小到大会TLE #include <cstdio> #include <cstring

SCOI2016 幸运数字

传送门 如果只是一条路径的话,那就是非常简单的线性基. 不过要考虑多组询问-- 考虑到n比较小,我们可以模仿倍增LCA的方法,预处理倍增的线性基.在每次路径上跳的时候把线性基合并最后求解即可.具体的做法是,我们用\(p[i][x][j]\)表示在编号为x的点处,向上跳\(2^i\)步以内,线性基第j位的数.这个可以合并,比较好写的方法就是直接传两个数组进去合并. 之后就正常了.代码很短,不到100行.(我交了好多次因为忘记用longlong快读了--) #include<iostream> #

[SCOI2016]幸运数字 线性基

题面 题面 题解 题面意思非常明确:求树上一条链的最大异或和. 我们用倍增的思想. 将这条链分成2部分:x ---> lca , lca ---> y 分别求出这2个部分的线性基,然后合并,再求最大异或和. 所以我们现在只需要考虑如何在树上求一条无需拐弯的链的最大线性基. 考虑倍增. 我们预处理出f[i][j]表示从点i开始向上走\(2^j\)构成的链的线性基.至于只有点\(i\)一个点的线性基,我们可以在运算的时候特判一下处理. 暴力预处理后,我们就可以最多 合并3次 + 求LCA的复杂度