2.给一个点数<=15的联通无向图的边定向,要求定向后存在一种方案使得1号点和2号点能到达同一个点。问合法方案数。
考虑容斥,每次选出两个分别包含1、2的联通块并让它们不相交,且没有横跨两个联通跨的边,那么答案就要减去$2^k*f[S]*g[S]$,其中k是两个点都不在联通块的边的数量,f表示包含点1且从1出发能够到达S中任意一个点的方案数,g同理。
由于f是恰好到达,因此仍然是容斥即可。具体见代码。复杂度O(3^n)。
1 #define mod 1000000007 2 #include<bits/stdc++.h> 3 using namespace std; 4 typedef long long int ll; 5 int n,m; 6 ll pow2[555],f[(1<<15)+1],g[(1<<15)+1]; 7 int a[555][2],b[(1<<15)+1]; 8 bool can[(1<<15)+1]; 9 inline void init() 10 { 11 pow2[0]=1; 12 for(int i=1;i<=500;++i) 13 pow2[i]=pow2[i-1]*2%mod; 14 can[0]=1; 15 for(int i=0;i<n;++i) 16 can[1<<i]=1; 17 for(int k=1;k<=n;++k) 18 for(int i=1;i<=m;++i) 19 { 20 int x=a[i][0],y=a[i][1]; 21 for(int S=0;S<(1<<n);++S) 22 { 23 if(S&(1<<x)) 24 can[S|(1<<y)]|=can[S]; 25 if(S&(1<<y)) 26 can[S|(1<<x)]|=can[S]; 27 } 28 } 29 } 30 bool vis[(1<<15)+1]; 31 inline int in(int S) 32 { 33 if(vis[S]) 34 return b[S]; 35 vis[S]=1; 36 int s=0; 37 for(int i=1;i<=m;++i) 38 if((S&(1<<a[i][0]))&&(S&(1<<a[i][1]))) 39 ++s; 40 return b[S]=s; 41 } 42 inline void solveF() 43 { 44 f[0]=1; 45 for(int S=1;S<(1<<n);++S) 46 { 47 if(!(S&1)) 48 continue; 49 if(!can[S]) 50 continue; 51 f[S]=pow2[in(S)]; 52 for(int s=(S-1)&S;s;s=(s-1)&S) 53 { 54 if(!(s&1)) 55 continue; 56 if(!can[s]) 57 continue; 58 f[S]=(f[S]-pow2[in(S^s)]*f[s]%mod+mod)%mod; 59 } 60 } 61 } 62 inline void solveG() 63 { 64 g[0]=1; 65 for(int S=1;S<(1<<n);++S) 66 { 67 if(!(S&2)) 68 continue; 69 if(!can[S]) 70 continue; 71 g[S]=pow2[in(S)]; 72 for(int s=(S-1)&S;s;s=(s-1)&S) 73 { 74 if(!(s&2)) 75 continue; 76 if(!can[s]) 77 continue; 78 g[S]=(g[S]-pow2[in(S^s)]*g[s]%mod+mod)%mod; 79 } 80 } 81 } 82 inline bool cross(int S1,int S2) 83 { 84 for(int i=1;i<=m;++i) 85 { 86 int x=a[i][0],y=a[i][1]; 87 if((S1&(1<<x))&&(S2&(1<<y))) 88 return true; 89 if((S1&(1<<y))&&(S2&(1<<x))) 90 return true; 91 } 92 return false; 93 } 94 inline void solve() 95 { 96 ll ans=pow2[m]; 97 for(int S1=0;S1<(1<<n);++S1) 98 { 99 if(!(S1&1)) 100 continue; 101 int S=((1<<n)-1)^S1; 102 for(int S2=S;S2;S2=(S2-1)&S) 103 { 104 if(!(S2&2)) 105 continue; 106 if(cross(S1,S2)) 107 continue; 108 if(!(can[S1]&&can[S2])) 109 continue; 110 ans=(ans-f[S1]*g[S2]%mod*pow2[in(S^S2)]%mod+mod)%mod; 111 } 112 } 113 cout<<ans<<endl; 114 } 115 int main() 116 { 117 ios::sync_with_stdio(false); 118 int useless; 119 cin>>n>>m>>useless; 120 for(int i=1;i<=m;++i) 121 { 122 cin>>a[i][0]>>a[i][1]; 123 --a[i][0],--a[i][1]; 124 } 125 init(); 126 solveF(); 127 solveG(); 128 solve(); 129 return 0; 130 }
3.一个字符串,从中划分出一些不相交的子串,要求第i+1个串是第i个串的严格子串。问做多划分多少个。
显然串的长度是[1,k],k是总个数。将这个字符串翻转过来,则要求第i个串是前一个串的子串且长度恰好+1。令fi以第i位结尾的最长划分个数,每次往后更新,相当于在SAM上定位到这个节点并且进行子树取max操作。由于要求不相交,相当于有一个时间的限制,用堆维护即可。
注意更新时要在parent tree上调到祖先节点去更新,如果访问过就break。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1E6+5; 4 int n; 5 namespace SAM 6 { 7 int tot=1,last=1; 8 int back[maxn*2]; 9 struct node 10 { 11 int fa,len,ch[26]; 12 }t[maxn*2]; 13 inline void insert(int x,int id) 14 { 15 int now=++tot,u=last; 16 last=tot; 17 back[id]=now; 18 t[now].len=t[u].len+1; 19 for(;u&&!t[u].ch[x];u=t[u].fa) 20 t[u].ch[x]=now; 21 if(!u) 22 t[now].fa=1; 23 else 24 { 25 int v=t[u].ch[x]; 26 if(t[v].len==t[u].len+1) 27 t[now].fa=v; 28 else 29 { 30 int w=++tot; 31 t[w]=t[v]; 32 t[w].len=t[u].len+1; 33 t[v].fa=t[now].fa=w; 34 for(;u&&t[u].ch[x]==v;u=t[u].fa) 35 t[u].ch[x]=w; 36 } 37 } 38 } 39 } 40 namespace TREE 41 { 42 int size,head[maxn*2]; 43 int dep[maxn*2],fa[maxn*2][20]; 44 int TI,dfn[maxn*2],low[maxn*2],where[maxn*2]; 45 struct edge 46 { 47 int to,next; 48 }E[maxn*2]; 49 struct pt 50 { 51 int time,u,v; 52 pt(int a=0,int b=0,int c=0):time(a),u(b),v(c){} 53 bool operator<(const pt&A)const 54 { 55 return time>A.time; 56 } 57 }; 58 inline void add(int u,int v) 59 { 60 E[++size].to=v; 61 E[size].next=head[u]; 62 head[u]=size; 63 } 64 inline void build() 65 { 66 for(int i=2;i<=SAM::tot;++i) 67 add(SAM::t[i].fa,i); 68 } 69 void dfs(int u,int d) 70 { 71 dep[u]=d; 72 fa[u][0]=SAM::t[u].fa; 73 for(int i=1;i<20;++i) 74 fa[u][i]=fa[fa[u][i-1]][i-1]; 75 dfn[u]=low[u]=++TI; 76 where[TI]=u; 77 for(int i=head[u];i;i=E[i].next) 78 { 79 int v=E[i].to; 80 dfs(v,d+1); 81 low[u]=low[v]; 82 } 83 } 84 inline int jump(int x,int d) 85 { 86 for(int i=19;i>=0;--i) 87 if(SAM::t[fa[x][i]].len>=d) 88 x=fa[x][i]; 89 return x; 90 } 91 int t[maxn*8]; 92 int f[maxn]; 93 void change(int L,int R,int l,int r,int x,int num) 94 { 95 if(L<=l&&r<=R) 96 { 97 t[num]=max(t[num],x); 98 return; 99 } 100 int mid=(l+r)>>1; 101 t[num<<1]=max(t[num<<1],t[num]); 102 t[num<<1|1]=max(t[num<<1|1],t[num]); 103 if(R<=mid) 104 change(L,R,l,mid,x,num<<1); 105 else if(mid<L) 106 change(L,R,mid+1,r,x,num<<1|1); 107 else 108 change(L,R,l,mid,x,num<<1),change(L,R,mid+1,r,x,num<<1|1); 109 } 110 inline int ask(int l,int r,int pos,int num) 111 { 112 if(l==r) 113 return t[num]; 114 int mid=(l+r)>>1; 115 t[num<<1]=max(t[num<<1],t[num]); 116 t[num<<1|1]=max(t[num<<1|1],t[num]); 117 if(pos<=mid) 118 return ask(l,mid,pos,num<<1); 119 else 120 return ask(mid+1,r,pos,num<<1|1); 121 } 122 bool vis[maxn*2]; 123 void solve() 124 { 125 change(1,TI,1,TI,1,1); 126 dfs(1,0); 127 for(int i=1;i<=n;++i) 128 f[i]=1; 129 priority_queue<pt>Q; 130 int ans=0; 131 for(int i=1;i<=n;++i) 132 { 133 while(!Q.empty()) 134 { 135 pt A=Q.top(); 136 if(i<A.time) 137 break; 138 Q.pop(); 139 change(dfn[A.u],low[A.u],1,TI,A.v,1); 140 } 141 int u=SAM::back[i]; 142 f[i]=ask(1,TI,dfn[u],1); 143 // cout<<i<<" "<<f[i]<<endl; 144 145 u=jump(u,f[i]); 146 int len=f[i]; 147 do 148 { 149 if(len) 150 Q.push(pt(len+i+1,u,len+1)); 151 vis[u]=1; 152 u=SAM::t[u].fa; 153 len=SAM::t[u].len; 154 }while(!vis[u]); 155 156 u=jump(SAM::back[i],f[i]); 157 for(int j=0;j<26;++j) 158 { 159 if(SAM::t[u].ch[j]) 160 Q.push(pt(f[i]+i+1,SAM::t[u].ch[j],f[i]+1));/* 161 if(SAM::t[u].ch[j]) 162 { 163 int v=SAM::t[u].ch[j]; 164 len=f[i]; 165 do 166 { 167 if(len) 168 Q.push(pt(len+i+1,v,len+1)); 169 vis[v]=1; 170 v=SAM::t[v].fa; 171 len=SAM::t[v].len; 172 }while(!vis[v]); 173 }*/ 174 } 175 ans=max(ans,f[i]); 176 } 177 cout<<ans<<endl; 178 } 179 } 180 string str; 181 int main() 182 { 183 // freopen("brr.in","r",stdin); 184 // freopen("brr.out","w",stdout); 185 ios::sync_with_stdio(false); 186 cin>>str; 187 n=str.size(); 188 reverse(str.begin(),str.end()); 189 // cout<<str<<endl; 190 str="!"+str; 191 for(int i=1;i<=n;++i) 192 SAM::insert(str[i]-'a',i); 193 TREE::build(); 194 TREE::solve(); 195 return 0; 196 } 197 //abcdbcdbcc