zoukankan      html  css  js  c++  java
  • [校内训练20_05_27]BC

    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
  • 相关阅读:
    敏捷开发 之 计划、测试 与 重构
    敏捷开发 之 理论概述篇
    第二十章 排查和调试Web程序 之 设计异常处理策略
    第十九章 排查和调试Web程序 之 防止和排查运行时问题
    第十八章 提升用户体验 之 减少带宽占用
    第十七章 提升用户体验 之 使用MVC扩展功能控制程序行为
    第十六章 提升用户体验 之 设计实现routes
    第十五章 提升用户体验 之 设计实现MVC controllers 和 actions
    第十四章 提升用户体验 之 设计实现国际化和本地化
    Nginx系统学习笔记(3)同一端口下设置Alias(虚拟目录)
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/13025084.html
Copyright © 2011-2022 走看看