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 }
View Code

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
View Code

 

 posted on 2020-06-01 14:39  GreenDuck  阅读(134)  评论(0编辑  收藏  举报