trac
10个串,问最小回文划分,只要任何一个串是回文即可
和一个串几乎相同,每个串分别维护以i结尾的回文串集合
#include
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const int inf = 2e8;
const int maxn = 100020;
const ll mod = 1e9 + 7;
struct Pali{
int total,anc[maxn],fail[maxn],len[maxn],last,son[maxn][26],hd[maxn],diff[maxn];
int S[maxn],m;
void init() //回文树初始化
{
S[0]=-1;
m=0; //字符串长度
total=1; //回文树点数
last=0; //最后插入的点
len[0]=0; //回文串长度
len[1]=-1;
fail[0]=fail[1]=1;
}
void insert(int ch)
{
S[++m]=ch;
int cur=last;
while (S[m-len[cur]-1]!=S[m]) cur=fail[cur];
if (!son[cur][ch])
{
len[++total]=len[cur]+2;
int tmp=fail[cur];
while (S[m-len[tmp]-1]!=S[m]) tmp=fail[tmp];
tmp=son[tmp][ch];
fail[total]=tmp; son[cur][ch]=total;
diff[total]=len[total]-len[tmp]; //间隔序列
anc[total]=(diff[total]==diff[tmp]? anc[tmp]:tmp); //开头位置
}
last=son[cur][ch];
}
}dt[11];
char a[12][maxn];
int n,k,ans[maxn];
void solve()
{
//cout<<(sizeof(dt) >> 20)<
for (int i = 1 ; i <= k ; i++) dt[i].init();
for (int i=1; i<=n; ++i) ans[i]=inf;
ans[1] = 1;
for (int i=1; i<=n; ++i)
{
for (int t = 1 ; t <= k ; t++){
dt[t].insert(a[t][i] - 'a');
for (int j=dt[t].last; j; j= dt[t].anc[j])
{
dt[t].hd[j]=i-dt[t].len[dt[t].anc[j]]-dt[t].diff[j]; //GPL存放位置
if (dt[t].anc[j]!=dt[t].fail[j] && ans[dt[t].hd[dt[t].fail[j]]]<ans[dt[t].hd[j]])
dt[t].hd[j]=dt[t].hd[dt[t].fail[j]];
if (ans[dt[t].hd[j]]+1<ans[i]) ans[i]=ans[dt[t].hd[j]]+1;
}
}
}
cout<<ans[n]<<endl;
//for (int i = 1 ; i <= n ; i++) cout<
}
int main(){
scanf("%d %d",&k,&n);
rep(i,1,k) scanf("%s",a[i] + 1);
solve();
}
转化后题意
在线询问两点可达性
走过的边只能标号都递增或者都递减
特殊性质是只会和标号差不超过k的点连边
2e5, k <= 200
题解
巧妙的分治
任意两点可达必定经过其间长度为k的区间
那么分治,在这两个点被分治区间中点隔开的地方统计
只需要用bitset维护当前区间的点到中间k个点分别走正向边和反向边的可达性
复杂度:O(nlogn * k / 64)
#include
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const ld inf = 2e18;
const int maxn = 200020;
const ll mod = 1e9 + 7;
bitset <220> bit[18][maxn],rbit[18][maxn];
vector <int> e[maxn],re[maxn];
int n,m,k,Q,a[maxn],ans[maxn],tot;
void solve(int dep,int l,int r){
if ( l == r ) return;
int mid = (l + r) >> 1;
solve(dep + 1,l,mid) , solve(dep + 1,mid + 1,r);
int R = mid + k / 2 , L = R - k + 1;
if ( r - l + 1 <= k ) L = l , R = r;
for (int i = L ; i <= r ; i++){
if ( i <= R ) rbit[dep][i][i - L] = 1;
for ( auto v : re[i] ){
if ( v >= l )
rbit[dep][i] |= rbit[dep][v];
}
}
for (int i = R ; i >= l ; i--){
if ( i >= L ) bit[dep][i][i - L] = 1;
for (auto v : e[i]){
if ( v <= r )
bit[dep][i] |= bit[dep][v];
}
}
}
void init(){
solve(0,1,n);
}
bool query(int dep,int l,int r,int L,int R){
if ( l == r ) return 1;
int mid = (l + r) >> 1;
//in this layer
if ( L <= mid && R > mid ){
return (bit[dep][L] & rbit[dep][R]).count();
}
if ( R <= mid ) return query(dep + 1,l,mid,L,R);
return query(dep + 1,mid + 1,r,L,R);
}
bool can(int u,int v){
if ( u == v ) return 0;
if ( u > v ) swap(u,v);
return query(0,1,n,u,v);
}
int main(){
scanf("%d %d %d",&n,&m,&k);
for (int i = 1 ; i <= m ; i++){
int x,y;
scanf("%d %d",&x,&y);
e[x].pb(y) , re[y].pb(x);
}
init();
scanf("%d",&Q);
for (int i = 1 ; i <= Q ; i++){
int x;
scanf("%d",&x);
if ( !tot || can(ans[tot],x) ) ans[++tot] = x;
}
printf("%d\n",tot);
for (int i = 1 ; i <= tot ; i++){
printf("%d ",ans[i]);
}
}