A. Journey Planning
略
B. Navigation System
略
C. World of Darkraft: Battle for Azathoth
略
D. Reachable Strings
注意到操作是可逆的,于是可以考虑将两个串分别操作到终态,判断终态是否相同。显然如果
′
0
′
'0'
′0′的个数不相同一定非法,否则考虑每次操作后,
′
0
′
'0'
′0′的位置的奇偶性不变,那么发现其实只需要比较每个对应的
′
0
′
'0'
′0′位置的奇偶性是否相同即可(因为肯定可以尽可能把这些
′
0
′
'0'
′0′往前移,使得只有最后面的
′
0
′
'0'
′0′后面的
′
1
′
'1'
′1′的长度可能
>
1
>1
>1)。
判断的时候可以用哈希实现,代码实际上是比较了差分后的奇偶性。时间复杂度
O
(
n
+
q
)
\mathcal O(n+q)
O(n+q)。
#include <bits/stdc++.h>
#define MOD1 914116871
#define MOD2 1004535809
using namespace std;
typedef long long ll;
const ll base1=11516,base2=166166;
ll powd1[200005],powd2[200005];
ll sum1[200005][2],sum2[200005][2];
char str[200005];
int cnt[200005],nxt[200005];
void pre(int n) {
powd1[0]=powd2[0]=1;
for(int i=1;i<=n;i++) {
cnt[i]=cnt[i-1]+(str[i]=='0');
powd1[i]=powd1[i-1]*base1%MOD1;
powd2[i]=powd2[i-1]*base2%MOD2;
if (str[i]=='0') {
sum1[i][0]=(sum1[i-1][0]*base1+'0')%MOD1;
sum1[i][1]=(sum1[i-1][0]*base1+'1')%MOD1;
sum2[i][0]=(sum2[i-1][0]*base2+'0')%MOD2;
sum2[i][1]=(sum2[i-1][0]*base2+'1')%MOD2;
}
else {
sum1[i][0]=sum1[i-1][1];
sum1[i][1]=sum1[i-1][0];
sum2[i][0]=sum2[i-1][1];
sum2[i][1]=sum2[i-1][0];
}
}
nxt[n+1]=n+1;
for(int i=n;i>0;i--) nxt[i]=((str[i]=='0')?i:nxt[i+1]);
}
bool equal(int x,int y,int len) {
if (cnt[x]-cnt[x-len]!=cnt[y]-cnt[y-len]) return 0;
int d=cnt[x]-cnt[x-len];
int r1=min(x,nxt[x-len+1]-1),r2=min(y,nxt[y-len+1]-1);
bool v1=((r1^(x-len))&1),v2=((r2^(y-len))&1);
if ((sum1[x][0]-sum1[x-len][v1]*powd1[d]%MOD1+MOD1)%MOD1
!=(sum1[y][0]-sum1[y-len][v2]*powd1[d]%MOD1+MOD1)%MOD1) return 0;
if ((sum2[x][0]-sum2[x-len][v1]*powd2[d]%MOD2+MOD2)%MOD2
!=(sum2[y][0]-sum2[y-len][v2]*powd2[d]%MOD2+MOD2)%MOD2) return 0;
return 1;
}
int main() {
int n;
scanf("%d%s",&n,str+1);
pre(n);
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
puts((equal(x+z-1,y+z-1,z))?"Yes":"No");
}
return 0;
}
E. Treeland and Viruses
显然考虑虚树,对于每次给定的
v
i
v_i
vi和
u
i
u_i
ui建出虚树。
考虑对虚树上每个节点
i
i
i求出
f
i
f_i
fi和
g
i
g_i
gi,分别表示点
i
i
i由哪个病毒感染和感染的时间,那么
f
i
f_i
fi相同的节点在虚树上形成连通块。那么可以直接跑一个dijkstra最短路,每次确定了某个点的
f
f
f和
g
g
g后考虑更新周围一圈没有确定的点,用优先队列维护即可。
时间复杂度为
O
(
(
n
+
q
+
∑
i
=
1
q
(
k
i
+
m
i
)
)
log
n
)
\mathcal O((n+q+\sum_{i=1}^{q}(k_i+m_i))\log n)
O((n+q+∑i=1q(ki+mi))logn)。
#include <bits/stdc++.h>
#define FR first
#define SE second
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> pr;
vector <int> e[200005];
int fa[200005][20],dep[200005];
int dfn[200005],dfs_cnt;
void dfs(int x) {
dfn[x]=++dfs_cnt;
dep[x]=dep[fa[x][0]]+1;
for(int i=0;i<e[x].size();i++)
if (e[x][i]!=fa[x][0]) {
int u=e[x][i];
fa[u][0]=x;
for(int j=1;j<20;j++) fa[u][j]=fa[fa[u][j-1]][j-1];
dfs(u);
}
}
int lca(int x,int y) {
if (dep[x]<dep[y]) swap(x,y);
int d=dep[x]-dep[y];
for(int i=0;i<20;i++)
if ((d>>i)&1) x=fa[x][i];
if (x==y) return x;
for(int i=19;i>=0;i--)
if (fa[x][i]!=fa[y][i]) {
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
vector <pr> ee[200005];
int st[200005],num[400005];
int node[200005],cnt;
inline void addEdge(int x,int y) {
int d=dep[y]-dep[x];
ee[x].push_back(pr(y,d));
ee[y].push_back(pr(x,d));
}
bool cmp(int x,int y) {
return dfn[x]<dfn[y];
}
void build(int k) {
sort(num+1,num+k+1,cmp);
int top;
st[top=1]=1;
cnt=0;
for(int i=1;i<=k;i++)
if (num[i]!=st[top]) {
int x=num[i],p=lca(x,st[top]);
for(;;) {
if (dep[p]<=dep[st[top-1]]) {
node[++cnt]=st[top];
addEdge(st[top-1],st[top]);
top--;
}
else if (dep[p]<dep[st[top]]) {
node[++cnt]=st[top];
addEdge(p,st[top]);
st[top]=p;
}
else break;
}
if (st[top]!=x) st[++top]=x;
}
for(;top;top--) {
node[++cnt]=st[top];
if (top>1) addEdge(st[top-1],st[top]);
}
}
struct Data {
int x,y,d;
Data() {}
Data(int a,int b,int c):x(a),y(b),d(c) {}
bool operator < (const Data & b) const {
if (y!=b.y) return y>b.y;
if (x!=b.x) return x>b.x;
return d>b.d;
}
};
typedef pair<Data,int> prr;
Data dis[200005];
bool vis[200005];
priority_queue <prr> q;
pr a[200005];
void solve(int k) {
for(int i=1;i<=cnt;i++) {
int x=node[i];
vis[x]=0;
dis[x]=Data(0,inf,0);
}
for(int i=1;i<=k;i++) {
int x=a[i].FR;
dis[x]=Data(i,0,0);
q.push(prr(dis[x],x));
}
while (!q.empty()) {
prr t=q.top();q.pop();
if (vis[t.SE]) continue;
int x=t.SE;
vis[x]=1;
for(int i=0;i<ee[x].size();i++)
if (!vis[ee[x][i].FR]) {
int u=ee[x][i].FR,d=ee[x][i].SE;
Data v(dis[x].x,(dis[x].d+d+a[dis[x].x].SE-1)/a[dis[x].x].SE,dis[x].d+d);
if (dis[u]<v) {
dis[u]=v;
q.push(prr(dis[u],u));
}
}
}
for(int i=1;i<=cnt;i++) {
int x=node[i];
vector<pr>().swap(ee[x]);
}
}
int val[200005];
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
dfs(1);
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++) {
int ki,mi;
scanf("%d%d",&ki,&mi);
int sz=0;
for(int j=1;j<=ki;j++) {
int x,y;
scanf("%d%d",&x,&y);
a[j]=pr(x,y);
num[++sz]=x;
}
for(int j=1;j<=mi;j++) {
scanf("%d",&val[j]);
num[++sz]=val[j];
}
build(sz);
solve(ki);
for(int j=1;j<=mi;j++) printf("%d ",dis[val[j]].x);
printf("\n");
}
return 0;
}
F. Blocks and Sensors
有点被降智了。。。
考虑一开始假设所有方块都是有颜色的,那么激光只会照到边缘的方块。对于一个边缘的方块,如果它被一束没有颜色的激光打到或者有两束不同颜色的激光打到它,那么它一定是没有颜色的,可以删去。不断重复这个过程直到没有可以删去的方块,这里可以用bfs实现。
操作完后考虑是否有一束有颜色的激光路径上所有方块都被删去,有的话显然无解,否则因为此时边缘的方块都会被相同且有颜色的激光所打到,直接染色就是合法方案了。
时间复杂度为
O
(
n
m
k
)
\mathcal O(nmk)
O(nmk)。
#include <bits/stdc++.h>
using namespace std;
int n,m,k;
inline int id(int x,int y,int z) {
return x*(m+2)*(k+2)+y*(k+2)+z;
}
int num[2000005],up[2000005];
bool vis[2000005];
struct Point {
int x,y,z;
Point() {}
Point(int a,int b,int c):x(a),y(b),z(c) {}
};
queue <Point> q;
bool bfs() {
for(int i=1;i<=m;i++)
for(int j=1;j<=k;j++) {
int u=id(0,i,j),v=id(n+1,i,j);
up[u]=1;
if (!vis[id(1,i,j)]) {
int t=id(1,i,j);
if (!num[u]||(num[t]!=-1&&num[t]!=num[u])) {
num[t]=0;
vis[t]=1;
q.push(Point(1,i,j));
}
else num[t]=num[u];
}
up[v]=n;
if (!vis[id(n,i,j)]) {
int t=id(n,i,j);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(n,i,j));
}
else num[t]=num[v];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++) {
int u=id(i,0,j),v=id(i,m+1,j);
up[u]=1;
if (!vis[id(i,1,j)]) {
int t=id(i,1,j);
if (!num[u]||(num[t]!=-1&&num[t]!=num[u])) {
num[t]=0;
vis[t]=1;
q.push(Point(i,1,j));
}
else num[t]=num[u];
}
up[v]=m;
if (!vis[id(i,m,j)]) {
int t=id(i,m,j);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(i,m,j));
}
else num[t]=num[v];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
int u=id(i,j,0),v=id(i,j,k+1);
up[u]=1;
if (!vis[id(i,j,1)]) {
int t=id(i,j,1);
if (!num[u]||(num[t]!=-1&&num[t]!=num[u])) {
num[t]=0;
vis[t]=1;
q.push(Point(i,j,1));
}
else num[t]=num[u];
}
up[v]=k;
if (!vis[id(i,j,k)]) {
int t=id(i,j,k);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(i,j,k));
}
else num[t]=num[v];
}
}
while (!q.empty()) {
Point t=q.front();q.pop();
int x=t.x,y=t.y,z=t.z;
int u=id(x,y,z);
int v=id(0,y,z);
while (up[v]<=n&&vis[id(up[v],y,z)]) up[v]++;
if (up[v]<=n&&!vis[id(up[v],y,z)]) {
int t=id(up[v],y,z);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(up[v],y,z));
}
else num[t]=num[v];
}
v=id(n+1,y,z);
while (up[v]&&vis[id(up[v],y,z)]) up[v]--;
if (up[v]&&!vis[id(up[v],y,z)]) {
int t=id(up[v],y,z);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(up[v],y,z));
}
else num[t]=num[v];
}
v=id(x,0,z);
while (up[v]<=m&&vis[id(x,up[v],z)]) up[v]++;
if (up[v]<=m&&!vis[id(x,up[v],z)]) {
int t=id(x,up[v],z);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(x,up[v],z));
}
else num[t]=num[v];
}
v=id(x,m+1,z);
while (up[v]&&vis[id(x,up[v],z)]) up[v]--;
if (up[v]&&!vis[id(x,up[v],z)]) {
int t=id(x,up[v],z);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(x,up[v],z));
}
else num[t]=num[v];
}
v=id(x,y,0);
while (up[v]<=k&&vis[id(x,y,up[v])]) up[v]++;
if (up[v]<=k&&!vis[id(x,y,up[v])]) {
int t=id(x,y,up[v]);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(x,y,up[v]));
}
else num[t]=num[v];
}
v=id(x,y,k+1);
while (up[v]&&vis[id(x,y,up[v])]) up[v]--;
if (up[v]&&!vis[id(x,y,up[v])]) {
int t=id(x,y,up[v]);
if (!num[v]||(num[t]!=-1&&num[t]!=num[v])) {
num[t]=0;
vis[t]=1;
q.push(Point(x,y,up[v]));
}
else num[t]=num[v];
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int l=1;l<=k;l++)
if (num[id(i,j,l)]==-1) num[id(i,j,l)]=0;
for(int i=1;i<=m;i++)
for(int j=1;j<=k;j++) {
if (num[id(0,i,j)]&&up[id(0,i,j)]>n) return 0;
if (num[id(n+1,i,j)]&&up[id(n+1,i,j)]<1) return 0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++) {
if (num[id(i,0,j)]&&up[id(i,0,j)]>m) return 0;
if (num[id(i,m+1,j)]&&up[id(i,m+1,j)]<1) return 0;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
if (num[id(i,j,0)]&&up[id(i,j,0)]>k) return 0;
if (num[id(i,j,k+1)]&&up[id(i,j,k+1)]<1) return 0;
}
return 1;
}
int main() {
memset(num,255,sizeof(num));
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=m;i++)
for(int j=1;j<=k;j++) scanf("%d",&num[id(0,i,j)]);
for(int i=1;i<=m;i++)
for(int j=1;j<=k;j++) scanf("%d",&num[id(n+1,i,j)]);
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++) scanf("%d",&num[id(i,0,j)]);
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++) scanf("%d",&num[id(i,m+1,j)]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) scanf("%d",&num[id(i,j,0)]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) scanf("%d",&num[id(i,j,k+1)]);
if (!bfs()) {
puts("-1");
return 0;
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
for(int l=1;l<=k;l++) printf("%d ",num[id(i,j,l)]);
printf("\n");
}
printf("\n");
}
return 0;
}