题目描述
小C曾经有一个神奇的字符串 S S S, S S S每一个字符都是非负整数。
但小C将字符串丢失了,唯一剩下的是他当时用 S A SA SA求出的一些 L C P LCP LCP信息。 L C P ( L o n g e s t C o m m o n P r e f i x ) LCP(Longest Common Prefix) LCP(LongestCommonPrefix),即最长公共前缀。
将
S
S
S的字符从1开始编号,设
n
=
∣
S
∣
n=|S|
n=∣S∣,用
S
i
,
j
S_{i,j}
Si,j表示
S
S
S的第
i
i
i个字符到第
j
j
j个字符构成的子串
则
L
C
P
(
i
,
j
)
=
max
i
+
k
≤
n
,
j
+
k
≤
n
,
S
i
,
i
+
k
=
S
j
,
j
+
k
{
k
+
1
}
LCP(i,j)=\max\limits_{i+k\leq n,j+k\leq n,S_{i,i+k}=S_{j,j+k}}\{k+1\}
LCP(i,j)=i+k≤n,j+k≤n,Si,i+k=Sj,j+kmax{k+1}
每条信息都是 x i , y i , z i x_i,y_i,z_i xi,yi,zi的形式,表示 L C P ( x i , y i ) = z i LCP(x_i,y_i)=z_i LCP(xi,yi)=zi
丢失的字符难以找回,现在小C只想你找到所有满足条件的字符串中,字典序最小的一个。
但是有些信息可能已经损坏,所以信息之间可能存在矛盾。
输入格式
第一行两个整数
n
,
m
n,m
n,m,表示字符串长度,信息个数
然后
m
m
m行,每行三个整数
x
i
,
y
i
,
z
i
x_i,y_i,z_i
xi,yi,zi,描述一条信息
保证
x
i
+
z
i
−
1
≤
n
.
y
i
+
z
i
−
1
≤
n
x_i+z_i-1\leq n.y_i+z_i-1\leq n
xi+zi−1≤n.yi+zi−1≤n
输出格式
输出满足条件的最小字符串,两个字符串之间用空格隔开。如果不存在这样的字符串,输出一个整数-1。
样例输入1
3 2
1 2 0
1 3 1
样例输出1
0 1 0
样例输入2
3 2
1 2 0
1 2 1
样例输出2
-1
数据范围
1 ≤ n , m ≤ 1000 1\leq n,m\leq 1000 1≤n,m≤1000
题解
首先,我们设 s i s_i si为 S S S的第 i i i个字符。因为 S x , x + z − 1 = S y , y + z − 1 S_{x,x+z-1}=S_{y,y+z-1} Sx,x+z−1=Sy,y+z−1,所以 s x + i = = s y + i ( 0 ≤ i < z ) s_{x+i}==s_{y+i}(0\leq i< z) sx+i==sy+i(0≤i<z),所以我们可以用并查集把一定相同的字符放在一起。
因为 z z z是最长公共前缀的长度,所以如果 x + z ≤ n x+z\leq n x+z≤n且 y + z ≤ n y+z\leq n y+z≤n,则一定满足 s x + z ≠ s y + z s_{x+z}\neq s_{y+z} sx+z=sy+z。若 x + z x+z x+z和 y + z y+z y+z在同一个连通块,则矛盾,输出-1。否则用 b i t s e t bitset bitset下的 z [ i ] z[i] z[i]数组存储不能与 i i i相等的字符。若 z [ i ] [ j ] = = 1 z[i][j]==1 z[i][j]==1,则 i i i与 j j j一定不相等
最后,从1开始给每个字符赋值。对于每个字符,如果它的连通块已经被赋值,则这个字符的值就是该联通块的值;否则给这个连通块赋值。首先,将连通块中的每一个点遍历一遍,将每个点不能与其相等的点列出,再遍历这些点。每次操作的时间复杂度为 O ( n 2 ) O(n^2) O(n2),但因为用了 b i t s e t bitset bitset,可以直接用或操作,会快很多。遍历必须与连通块不相等的点,如果这个点未被赋值,则跳过;否则将这个点的值放入集合 S S S中。 m e x ( S ) mex(S) mex(S)就是这个连通块的值。 m e x mex mex可以 O ( n ) O(n) O(n)求出。
每次操作时间复杂度为 O ( n 2 ) O(n^2) O(n2),所以总时间复杂度为 O ( n 3 ) O(n^3) O(n3)。因为跑不满,而且用了 b i t s e t bitset bitset,所以是可以过的。
code
#include<bits/stdc++.h>
using namespace std;
int n,m,fl=0,a[1005],ans[1005],fa[1005],b[1005];
bitset<1005>p,v,z[1005],t[1005];
struct node{
int x,y,z;
}w[1005];
int find(int ff){
if(fa[ff]!=ff) fa[ff]=find(fa[ff]);
return fa[ff];
}
void pt(int x,int y){
int v1=find(x),v2=find(y);
if(v1!=v2) fa[v1]=v2;
}
void dd(int x,int y,int k){
for(int i=0;i<k;i++){
if(z[x+i][y+i]){
fl=1;return;
}
pt(x+i,y+i);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&w[i].x,&w[i].y,&w[i].z);
z[w[i].x+w[i].z][w[i].y+w[i].z]=z[w[i].y+w[i].z][w[i].x+w[i].z]=1;
}
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=m;i++){
dd(w[i].x,w[i].y,w[i].z);
if(fl){
printf("-1");
return 0;
}
}
for(int i=1;i<=n;i++){
a[i]=-1;t[find(i)][i]=1;
}
for(int i=1;i<=n;i++){
int v=fa[i];
if(a[v]==-1){
for(int j=0;j<=n;j++){
b[j]=p[j]=0;
}
for(int j=1;j<=n;j++){
if(t[v][j]) p=p|z[j];
}
for(int j=1;j<=n;j++){
if(p[j]&&a[fa[j]]!=-1) b[a[fa[j]]]=1;
}
for(int j=0;j<=n;j++){
if(b[j]==0){
a[v]=j;break;
}
}
}
ans[i]=a[v];
}
for(int i=1;i<=n;i++){
printf("%d ",ans[i]);
}
}
1109

被折叠的 条评论
为什么被折叠?



