题目
解题思路
可以想到,将字符串排序之后,字符串a与字符串b连边表示a和b只能够选一个。然后问题转化为给图上的点染色,边连着的两点颜色不能相同。问最少有多少种颜色。不会。
学习了网络流模型的转化后,可以转化为匹配(最小割模型)。将前缀类型和后缀类型视为一个个点,S向前缀类型连边,后缀类型向T连边,容量为1,对应的前缀类型和后缀类型连的边,容量为正无穷,表示这条边不能割。
另外一种直接的模型就是二分图匹配了。与网络图中的边的意义一样,表示选了某个前缀类型后,就不能够选对应的后缀类型。
其实这两种方法具有相通性。
问方案?随便搞搞。判断一下哪种前缀/后缀类型算进了答案,对应的方案跑一下图就是了。
某位大神的代码
inline int preprocessing(int pre[]) {
std::sort(id + 1, id + n + 1, cmp);
pre[id[1]] = 1;
for (int i = 2; i <= n; ++i)
pre[id[i]] = pre[id[i - 1]] + (strncmp(s[id[i - 1]], s[id[i]], k) != 0);
return pre[id[n]];
}
for (int i = 1; i <= n; ++i) std::reverse(s[i], s[i] + strlen(s[i]));
这样能够大大缩短代码长度。(给字符串排序)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define N 3000010
#define M 5010
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note{
int to,next;
};note edge[M],edge1[M];
int tot,head[M*2],tot1,head1[M*2];
int i,j,K,k,ans;
int n,m,x,gx,gy,cnt,c1;
char ch,s[N];
int col[M],o[M];
int hl[M],hr[M];
int oL[M],oR[M];
int L[M],R[M],len[M],L1[M],R1[M];
int fl[M],fr[M],match[M*2];
int bz[M*2];
bool vis[M*2];
queue<int>Q;
vector<int>grp[M*2];
int read(){
int fh=1,res=0;char ch;
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();
return fh*res;
}
void write(int x){if(x>9)write(x/10);P(x%10+'0');}
void mi(int &x,int y){x=x<y?x:y;}
void ma(int &x,int y){x=x>y?x:y;}
int getl(int x){return fl[x]==x?x:fl[x]=getl(fl[x]);}
int getr(int x){return fr[x]==x?x:fr[x]=getr(fr[x]);}
int cl(int l1,int l2){
l1=L1[l1];
int i,l=len[l1]<len[l2]?len[l1]:len[l2];
fo(i,1,l)
if(s[L[l1]+i-1]>s[L[l2]+i-1])return 2;else
if(s[L[l1]+i-1]<s[L[l2]+i-1])return 1;
if(len[l1]>len[l2])return 2;
if(len[l1]<len[l2])return 1;
return 0;
}
int cr(int l1,int l2){
l1=R1[l1];
int i,l=len[l1]<len[l2]?len[l1]:len[l2];
fo(i,1,l)
if(s[R[l1]-i+1]>s[R[l2]-i+1])return 2;else
if(s[R[l1]-i+1]<s[R[l2]-i+1])return 1;
if(len[l1]>len[l2])return 2;
if(len[l1]<len[l2])return 1;
return 0;
}
void ql(int l,int r){
int i=l,j=r,mid=L1[(l+r)/2];
while(i<j){
while(cl(i,mid)==1)i++;
while(cl(j,mid)==2)j--;
if(i<=j)swap(L1[i],L1[j]),i++,j--;
}
if(l<j)ql(l,j);
if(i<r)ql(i,r);
}
void qr(int l,int r){
int i=l,j=r,mid=R1[(l+r)/2];
while(i<j){
while(cr(i,mid)==1)i++;
while(cr(j,mid)==2)j--;
if(i<=j)swap(R1[i],R1[j]),i++,j--;
}
if(l<j)qr(l,j);
if(i<r)qr(i,r);
}
void get_hl(){
int i,j,l,a1,b1;
fo(i,1,n-1){
a1=L1[i];b1=L1[i+1];
l=len[a1]<len[b1]?len[a1]:len[b1];
fo(j,1,l){
if(s[L[a1]+j-1]!=s[L[b1]+j-1])
break;
}
hl[i]=j-1;
}
}
void get_hr(){
int i,j,l,a1,b1;
fo(i,1,n-1){
a1=R1[i];b1=R1[i+1];
l=len[a1]<len[b1]?len[a1]:len[b1];
fo(j,1,l){
if(s[R[a1]-j+1]!=s[R[b1]-j+1])
break;
}
hr[i]=j-1;
}
}
void conl(int x,int y){gx=getl(x);gy=getl(y);if(gx!=gy)fl[gy]=gx;}
void conr(int x,int y){gx=getr(x);gy=getr(y);if(gx!=gy)fr[gy]=gx;}
void lb(int x,int y){edge[++tot].to=y;edge[tot].next=head[x];head[x]=tot;}
void lb1(int x,int y){edge1[++tot1].to=y;edge1[tot1].next=head1[x];head1[x]=tot1;}
bool find(int x){
int i;
for(i=head[x];i;i=edge[i].next)
if(bz[edge[i].to]!=bz[0]){
bz[edge[i].to]=bz[0];
if(!match[edge[i].to]||find(match[edge[i].to])){
match[edge[i].to]=x;
return 1;
}
}
return 0;
}
void work(){
int i,hd=0,tl=1,x;
fo(i,c1+1,c1+cnt)if(!match[i])Q.push(i);else col[i]=1;
while(!Q.empty()){
x=Q.front();Q.pop();
vis[x]=1;
col[x]=0;
for(i=head1[x];i;i=edge1[i].next)
if(!vis[edge1[i].to]){
vis[edge1[i].to]=1;
col[edge1[i].to]=1;
if(match[edge1[i].to])Q.push(match[edge1[i].to]);
}
}
}
int main(){
n=read();K=read();
fo(i,1,n){
L[i]=R[i]=R[i-1]+1;R[i]--;
ch=getchar();
while(ch<'A'||ch>'Z')ch=getchar();
while(ch>='A'&&ch<='Z')s[++R[i]]=ch,ch=getchar();
len[i]=R[i]-L[i]+1;
L1[i]=R1[i]=i;
}
ql(1,n);
qr(1,n);
fo(i,1,n)oL[L1[i]]=oR[R1[i]]=i;
get_hl();
get_hr();
fo(i,1,n)fl[i]=fr[i]=i;
fo(i,1,n-1)if(hl[i]>=K)conl(i,i+1);
fo(i,1,n-1)if(hr[i]>=K)conr(i,i+1);
memcpy(o,fl,sizeof(o));
sort(o+1,o+n+1);cnt=unique(o+1,o+n+1)-o-1;
fo(i,1,n)fl[i]=lower_bound(o+1,o+cnt+1,fl[i])-o;
c1=cnt;
memcpy(o,fr,sizeof(o));
sort(o+1,o+n+1);cnt=unique(o+1,o+n+1)-o-1;
fo(i,1,n)fr[i]=lower_bound(o+1,o+cnt+1,fr[i])-o;
fo(i,1,n)fr[i]+=c1;
fd(i,n,1){
lb(fl[oL[i]],fr[oR[i]]),lb1(fr[oR[i]],fl[oL[i]]);
}
fo(i,1,c1)if(!match[i]){
bz[0]++;bz[i]=bz[0];
ans+=find(i);
}
write(ans),P('\n');
fo(i,1,c1+cnt)match[match[i]]=i;
work();
fo(i,1,n){
gx=col[fl[oL[i]]]?fl[oL[i]]:fr[oR[i]];
grp[gx].push_back(i);
}
fo(i,1,M-20)if(grp[i].size()){
write(grp[i].size());P(' ');
fo(j,0,grp[i].size()-1)write(grp[i][j]),P(' ');
P('\n');
}
return 0;
}