zoukankan      html  css  js  c++  java
  • CF331E2 Deja Vu

    Link
    我们考虑两类路径:
    (0)类:字符路径只比点路径少了最后一个字符。
    (1)类:字符路径与点路径相等。
    (2)类:字符路径只比点路径少了第一个字符。
    (f_{flg,u,l})表示到(u)点结束,长度为(l)(flg)类路径条数。
    那么长度为(l)的合法路径条数就是(sumlimits_{u=1}^nf_{1,u,l})
    初始状态为(f_{0,u,0}=1)
    转移就是加一条路径接在当前路径的后面,按(flg)状态分成四类讨论:

    (0 ightarrow0)

    接在后面的一定是一条(0)类路径,而它的最后一条边((u,v))上的字符串一定以(u)结尾。
    那么我们枚举这样的边,从该边暴力往前拓展,得到一条可能合法的(0)类路径((p,v))
    如果该路径合法,那么它会造成转移(f_{0,p,l} ightarrow f_{0,v,l+len(p,v)})

    (1 ightarrow1)

    接在后面的一定是一条(2)类路径,而它的第一条边((u,v))上的字符串一定以(v)开头。
    那么我们枚举这样的边,从该边暴力往前拓展,得到一条可能合法的(2)类路径((p,v))
    如果该路径合法,那么它会造成转移(f_{1,p,l} ightarrow f_{1,v,l+len(p,v)})

    (1 ightarrow0)

    对于任意一条字符串为空的边((u,v)),它会造成转移(f_{1,u,l} ightarrow f_{1,v,l+1})

    (0 ightarrow1)

    接在后面的一定是一条(1)类路径,这条路径上一定存在一条边((u,v))满足(uv)是该边上的字符串的子串。
    那么我们枚举这样的边,从该边暴力往两头拓展,得到一条可能的(1)类路径((p,q))
    如果该路径合法,那么它会造成转移(f_{0,p,l} ightarrow f_{1,q,l+len(p,q)})

    不难发现转移可以写成((o,o',u,v,Delta))的形式,对每条上述提到的类型的边预处理这样的五元组,然后再根据拓扑序(按(l)升序)对(f)转移即可。
    时间复杂度为(O(n^3))
    E1找路径的做法包含在(0 ightarrow1)转移部分了。

    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using std::deque;
    const int N=57,P=1000000007;
    int n,m,f[2][N][2*N],e[N][N];std::vector<int>str[N][N],trans[2][2][N][N];
    int read(){int x;scanf("%d",&x);return x;}
    void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
    int extend(deque<int>&q,deque<int>::iterator it,int o)
    {
        int flg=1;
        if(!~o)
    	for(auto pre=prev(it);it!=q.begin()&&(int)q.size()<=n+n;it=pre,pre=prev(it))
    	    flg&=e[*pre][*it],q.insert(q.begin(),str[*pre][*it].begin(),str[*pre][*it].end());
        else
    	for(auto nex=next(it);nex!=q.end()&&(int)q.size()<=n+n;it=nex,nex=next(it))
    	    flg&=e[*it][*nex],q.insert(q.end(),str[*it][*nex].begin(),str[*it][*nex].end());
        return flg&((int)q.size()<=n+n);
    }
    void init()
    {
        for(int i=1;i<=n;++i)
    	for(int j=1;j<=n;++j)
    	    if(str[i][j].size()&&str[i][j].back()==i)
    	    {
    		deque<int>q(str[i][j].begin(),str[i][j].end());
    		if(extend(q,prev(q.end()),-1)) trans[0][0][q.front()][j].push_back((int)q.size());
    	    }
        for(int i=1;i<=n;++i)
    	for(int j=1;j<=n;++j)
    	{
    	    auto p=std::find(str[i][j].begin(),str[i][j].end(),i);
    	    if(p==str[i][j].end()||++p==str[i][j].end()||*p!=j) continue;
    	    deque<int>q(str[i][j].begin(),str[i][j].end());
    	    auto it=q.begin()+(p-str[i][j].begin())-1;
    	    if(extend(q,it,-1)&&extend(q,it+1,1)) trans[0][1][q.front()][q.back()].push_back((int)q.size()-1);
    	}
        for(int i=1;i<=n;++i)
    	for(int j=1;j<=n;++j)
    	    if(e[i][j]&&str[i][j].empty())
    		trans[1][0][i][j].push_back(1);
        for(int i=1;i<=n;++i)
    	for(int j=1;j<=n;++j)
    	    if(str[i][j].size()&&str[i][j].front()==j)
    	    {
    		deque<int>q(str[i][j].begin(),str[i][j].end());
    		if(extend(q,q.begin(),1)) trans[1][1][i][q.back()].push_back((int)q.size());
    	    }
    }
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;++i) f[0][i][0]=1;
        for(int i=1,u,v,k;i<=m;++i) for(u=read(),v=read(),k=read(),e[u][v]=1;k;--k) str[u][v].push_back(read());
        init();
        for(int l=0;l<n+n;++l)
    	for(int i=0;i<2;++i)
    	    for(int j=1;j<=n;++j)
    		if(f[i][j][l])
    		    for(int p=0;p<2;++p)
    			for(int q=1;q<=n;++q)
    			    for(int x:trans[i][p][j][q])
    				if(x+l<=n+n)
    				    inc(f[p][q][x+l],f[i][j][l]);
        for(int i=1;i<=n+n;++i)
        {
    	int sum=0;
    	for(int j=1;j<=n;++j) inc(sum,f[1][j][i]);
    	printf("%d
    ",sum);
        }
    }
    
  • 相关阅读:
    马士兵_聊天系统_知识储备库
    最近一些情况
    JAVA坦克大战项目练习日4
    JAVA坦克大战项目练习日3
    JAVA坦克大战项目练习日2
    JAVA坦克大战项目练习日1
    课后实战String的一些细节
    Java从入门到精通之数组篇
    58_自定义标签打包以及使用自定义标签教程
    javaWeb安全篇(1)——防盗链技术的实现
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12918017.html
Copyright © 2011-2022 走看看