题面
异或
给一个长度为 n n n 的序列 a a a, q q q 次询问在 a [ l . . . r ] a[l...r] a[l...r] 中选择若干个数 (可以不选) 和 d d d 异或所能得到的最大值。
1 ≤ n , q ≤ 1 0 6 , 0 ≤ a i < 2 30 1\leq n,q\leq 10^6\;,\;0\leq a_i< 2^{30} 1≤n,q≤106,0≤ai<230
不强制在线,出题人提供快读快输。
公交旅行
城市中有 n n n 个站台和 m m m 条公交线路,第 i i i 条公交线路由 t i t_i ti 个站台组成,记为 s i , 1 , s i , 2 , . . . , s i , t i s_{i,1}, s_{i,2}, ...,s_{i,t_i} si,1,si,2,...,si,ti。在 0 时刻,第 i i i 辆公交车会处在 s i , 1 s_{i,1} si,1 站台,之后每个时刻公交都会到达路线中的下一个站台。当公交到达终点站后,它下一个时刻将会回到出发的站台,注意一座站台可能在一条线路中出现多次,但不会相邻。
在 0 时刻,你处在站台 1 。如果在某一时刻你和公交在同一个站台,那么你就可以上这辆公交车,并在任意时刻下车,上下车的过程并不会花费时间。作为一位环保的优秀旅行家,你热爱乘坐公交出行。现在你想要知道,如果只乘坐公交出行,分别能最早在何时到达每个站台,或者判断这是不可能的。
注意,你一次只能乘坐一辆车,但在通往某个站台的过程中,可以乘坐许多辆不同的公交车。
n , m ≤ 1 0 5 , ∑ t i ≤ 2 × 1 0 5 n,m\leq10^5\;,\;\sum t_i\leq 2×10^5 n,m≤105,∑ti≤2×105
题解
异或
通过观察数据范围不难发现,这道题要求复杂度在 O ( n log n ) O(n\log n) O(nlogn) 以内。
任选若干个数与 d 异或,我们不难想到用异或线性基,只是要运用得更灵活些。
具体地,线性基的每一位额外存一个 p o s pos pos ,表示这个可供异或的数出现的位置。把询问离线,用扫描线从左往右扫,把数加入线性基,扫描到右端点时我们来查询答案。因此在线性基里我们得尽量让 p o s pos pos 变大(靠右),这个贪心策略可以尽可能的满足询问对区间的要求。
在线性基里,插入一个数时,若该位原先有值,那么保留 p o s pos pos 更大的,用 p o s pos pos 更小的去更新下面的位。具体地,若线性基里该位已存的数为 y y y ,位置为 p o s y pos_y posy ,要加入的数为 x x x(此时 x x x 的这一位应该为 1,不然进不来) ,位置为 p o s x pos_x posx,若 p o s x > p o s y pos_x>pos_y posx>posy 那么 s w a p ( x , y ) , s w a p ( p o s x , p o s y ) swap(x,y),swap(pos_x,pos_y) swap(x,y),swap(posx,posy),表示把 x x x 放到这一位上,然后拿 y y y 继续跑。然后不管怎样,不要忘了 x = x x o r y x=x\;xor\;y x=xxory (若已经 s w a p swap swap ,则应该是新的 x x x 和新的 y y y)再继续下一位。
这样一来,最靠右的位置尽量放高位,其他位置也没浪费,当我们对 d d d 进行查询时,只考虑 p o s ≥ l i pos\geq l_i pos≥li 的数,就能尽量保证高位被异或,进而保证答案最大化。
这应该是做过的一道原题。
CODE #1
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1000005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#pragma GCC optimize(2)
inline LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int qr;
// getchar
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
// print the remaining part
inline void flush () {
fwrite (obuf, 1, oS - obuf, stdout);
oS = obuf;
}
// putchar
inline void putc (char x) {
*oS ++ = x;
if (oS == oT) flush ();
}
// input a integer
template <class I>
inline void gi (I &x) {
for (c = gc(); c < '0' || c > '9'; c = gc());
for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
}
// print a integer
template <class I>
inline void print (I &x) {
if (!x) putc ('0');
while (x) qu[++ qr] = x % 10 + '0', x /= 10;
while (qr) putc (qu[qr --]);
}
}
using io :: gi;
using io :: putc;
using io :: print;
const int MOD = 1000000007;
int n,m,i,j,s,o,k;
int L[MAXN],R[MAXN],d[MAXN];
int a[MAXN];
vector<int> bu[MAXN];
int as[MAXN];
int bt[105],rr[105];
void ins(int x,int ad) {
for(int i = 29;i >= 0;i --) {
if(x & (1<<i)) {
if(!bt[i]) bt[i] = x,rr[i] = ad;
else if(ad > rr[i]) swap(bt[i],x),swap(rr[i],ad);
x ^= bt[i];
}
}
return ;
}
int main() {
freopen("xor.in","r",stdin);
freopen("xor.out","w",stdout);
gi(n);
for(int i = 1;i <= n;i ++) {
gi(a[i]);
}
gi(m);
for(int i = 1;i <= m;i ++) {
gi(L[i]); gi(R[i]); gi(d[i]);
bu[R[i]].push_back(i);
}
for(int i = 1;i <= n;i ++) {
ins(a[i],i);
for(int j = 0;j < (int)bu[i].size();j ++) {
int y = bu[i][j],D = d[y];
for(int k = 29;k >= 0;k --) {
if(!(D & (1<<k)) && rr[k] >= L[y]) {
D ^= bt[k];
}
}
as[y] = D;
}
}
for(int i = 1;i <= m;i ++) {
print(as[i]);
putc('\n');
}
io::flush();
return 0;
}
公交旅行
如果坐同一辆公交车连续经过几个站,我们可以等价地认为在中间的每一站都瞬间下车然后瞬间上车,那么就可以抽象成有 ∑ t i \sum t_i ∑ti 条费时为 1 的道路,第 i i i 条道路连接两个站点 u i , v i u_i,v_i ui,vi,该道路开放的时间点 T i T_i Ti 满足 T i ≡ k i ( m o d P i ) T_i\equiv k_i\;\;(\!\!\!\mod P_i) Ti≡ki(modPi) 。
实际上这就是一个不太好建图的最短路问题,边权是不定的(跟到达这个点的时间有关),但是容易发现我们肯定是能早到就早到,所以只要不把图建出来,每次实时获得边权,然后跑最短路就可以获得满分了。
CODE #2
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#pragma GCC optimize(2)
inline LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return f * x;
}
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int qr;
// getchar
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
// print the remaining part
inline void flush () {
fwrite (obuf, 1, oS - obuf, stdout);
oS = obuf;
}
// putchar
inline void putc (char x) {
*oS ++ = x;
if (oS == oT) flush ();
}
// input a integer
template <class I>
inline void gi (I &x) {
for (c = gc(); c < '0' || c > '9'; c = gc());
for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
}
// print a integer
template <class I>
inline void print (I &x) {
if (!x) putc ('0');
while (x) qu[++ qr] = x % 10 + '0', x /= 10;
while (qr) putc (qu[qr --]);
}
}
using io :: gi;
using io :: putc;
using io :: print;
const int MOD = 1000000007;
int n,m,i,j,s,o,k;
int ti[MAXN];
vector<int> ad[MAXN];
struct it{
int v;LL w;it(){v=w=0;}
it(int V,LL W){v=V;w=W;}
};
bool operator < (it a,it b) {return a.w < b.w;}
bool operator > (it a,it b) {return b < a;}
priority_queue<it,vector<it>,greater<it> > b;
vector<it> q[MAXN];
LL dp[MAXN];
bool f[MAXN];
int main() {
freopen("bus.in","r",stdin);
freopen("bus.out","w",stdout);
gi(n); gi(m);
for(int i = 1;i <= m;i ++) {
gi(ti[i]);
for(int j = 0;j < ti[i];j ++) {
gi(s);
ad[i].push_back(s);
q[s].push_back(it(i,(LL)j));
}
}
dp[0] = 1e18;
for(int i = 2;i <= n;i ++) {
dp[i] = 1e18;
}
dp[1] = 0;
b.push(it(1,0));
while(!b.empty()) {
it t = b.top();b.pop();
if(f[t.v]) continue;
dp[t.v] = t.w;
f[t.v] = 1;
for(int i = 0;i < (int)q[t.v].size();i ++) {
it tt = q[t.v][i];
int y = tt.v;
LL adr = tt.w;
int y2 = ad[y][(adr+1) % ti[y]];
if(f[y2]) continue;
adr -= t.w;
((adr %= ti[y]) += ti[y]) %= ti[y];
adr += t.w;
b.push(it(y2,adr+1ll));
}
}
for(int i = 2;i <= n;i ++) {
if(dp[i] < 1e18) print(dp[i]),putc(' ');
else putc('-'),putc('1'),putc(' ');
}putc('\n');
io :: flush();
return 0;
}