Codeforces Round 1320 简要题解

16 篇文章 0 订阅
5 篇文章 1 订阅

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值