F. Cooking
题意:
给定若干
01
01
01串,求它们的最长公共前后缀长度之和。
思路:
多模式串匹配,首先考虑
A
C
AC
AC自动机
如果我们不考虑最长的限制,只需要对所有的字符串从结尾开始跳
f
a
i
l
fail
fail,跳到的点一定是一个公共前后缀。于是我们每跳到一个点会产生贡献
s
i
∗
l
e
n
i
s_i*len_i
si∗leni,其中
s
i
s_i
si是节点
i
i
i出现的次数,
l
e
n
i
len_i
leni是这个位置代表的子串长度,最终答案就是
∑
s
i
∗
l
e
n
i
\sum s_i*len_i
∑si∗leni
现在我们加上最长的限制,于是
f
a
i
l
fail
fail链上不再是所有的点都满足要求了,现在我们只想要每个字符串上在
f
a
i
l
fail
fail树上深度最深的那个点,这显然是很难做到的。
每个点在
f
a
i
l
fail
fail树上的对应的最深的点为
m
i
m_i
mi,其实也就是该字串的最大
b
o
r
d
o
r
bordor
bordor,对所有的字符串都做一次
k
m
p
kmp
kmp我们就可以得到所有的
b
o
r
d
o
r
bordor
bordor
将
l
e
n
i
len_i
leni重新定义为点
i
i
i到点
m
i
m_i
mi距离的差值,这样就相当于将原本一段的长度,划分成了多段,因为字符串的一个
b
o
r
d
o
r
bordor
bordor一定会在
f
a
i
l
fail
fail上出现,所以对答案没有影响
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e6+7;
char s[105];
int trie[maxn][10],fail[maxn],cnt,son[maxn],root[maxn],Next[105],w[maxn],ans;
void getnext(char m[])
{
Next[0]=-1;
int k=-1,j=0;
int l=strlen(m);
while(j<l)
{
if(k==-1||m[k]==m[j])
{
k++;j++;
Next[j]=k;
}else
k=Next[k];
}
}
int insert(char s[])
{
int p=0,l=strlen(s);
for(int i=0;i<l;i++)
{
int u=s[i]-'0';
if(!trie[p][u])
{
trie[p][u]=++cnt;
}
p=trie[p][u];
w[p]=i-Next[i+1]+1;
son[p]++;
}
return p;
}
void make_fail()
{
queue<int>q;
for(int i=0;i<10;i++)
if(trie[0][i])
q.push(trie[0][i]);
while(!q.empty())
{
int t=q.front();
q.pop();
for(int i=0;i<10;i++)
{
int p=trie[t][i];
if(!p) trie[t][i]=trie[fail[t]][i];
else
{
fail[p]=trie[fail[t]][i];
q.push(p);
}
}
}
}
void dfs(int u)
{
if(u==0) return;
ans+=son[u]*w[u];
u=fail[u];
dfs(u);
}
signed main()
{
int n;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s);
getnext(s);
Next[0]=0;
root[i]=insert(s);
}
make_fail();
for(int i=1;i<=n;i++)
{
dfs(root[i]);
}
printf("%lld\n",ans);
}
G. Matrix Repair
题意:
类似数独游戏,给定一个01矩阵和该矩阵每行每列的异或和。现在矩阵中部分值缺失,询问能否唯一复原该矩阵。
题解:
为了使解唯一,那么填的数字自然也就是每行/每列恰好只缺一个空的数字,十分显然的想到拓扑排序
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int maxn=2e5+7;
int n,a[1005][1005],l[1005],c[1005],nl[1005],nc[1005];
int xorl[1005],xorc[1005],call[1005],calc[1005];
int vis[1005][1005];
int main()
{
scanf("%d",&n);
int cnt=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
if(a[i][j]==-1) continue;
cnt++;
nl[i]++;nc[j]++;
call[i]^=a[i][j];calc[j]^=a[i][j];
}
}
queue<PII>q;
for(int i=1;i<=n;i++) scanf("%d",&xorl[i]);
for(int i=1;i<=n;i++) scanf("%d",&xorc[i]);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((nl[i]==n-1||nc[j]==n-1)&&a[i][j]==-1)
q.push({i,j}),vis[i][j]=1;
}
}
while(!q.empty())
{
auto [x,y]=q.front();
q.pop();
cnt++;
if(nl[x]==n-1) a[x][y]=call[x]^xorl[x];
else a[x][y]=calc[y]^xorc[y];
call[x]=call[x]^a[x][y];calc[y]=calc[y]^a[x][y];
nl[x]++;nc[y]++;
if(nl[x]==n-1)
{
for(int i=1;i<=n;i++)
if(a[x][i]==-1 && vis[x][i]==0) q.push({x,i}),vis[x][i]=1;
}
if(nc[y]==n-1)
{
for(int i=1;i<=n;i++)
if(a[i][y]==-1 && vis[i][y]==0) q.push({i,y}),vis[i][y]=1;
}
}
if(cnt==n*n)
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
printf("%d ",a[i][j]);
puts("");
}
else
puts("-1");
}