• [实验舱 CSP/NOIP新赛制内部挑战赛5] B.小F的编码(BFS/DP)


    Problem

    题目地址

    Solution

    • 考虑一个简化版问题:给定长度为 (m) 的字符串 (S),和一些模式串 (c_i),问有多少种方案拼成 (S)

    • 思路:(f[i]) 表示有多少种方案拼成 (S[1...i]),那么有转移 (f[i]=sum_{c_x=S[k...i]} f[k]),答案就是 (f[m])具体的,看作有 (m+1) 个点,若 (c_x = S[k...i]),则在 (k->i) 连一条边,最统计有多少种从 (0)(m) 的路径。

    题解

    (f[i,j]) 表示第 (i) 个字符串匹配了 (j) 位是否可达。

    同样把 ((i,j)) 这个状态看成一个点。((i,j)->(u,v)) 之间有边则说明可以将 (c_u) 接上去,即满足:(S_i[j...len]=S_u[1...v])

    注意处理一些细节。初始状态 (f[i,0]=1),最终看是否有 (f[i,n]=1)。状态数 (O(nL)),建边复杂度 (O(n^2L^2)),时间复杂度 (O(n^2L^2))

    Code

    Talk is cheap.Show me the code.

    #include<bits/stdc++.h>
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
        return x * f;
    }
    typedef pair<int,int> PII;
    const int N = 57, maxn = N*N;
    int n,cnt;
    int head[maxn];
    int f[N][N];
    char str[N][N];
    struct Edge {
    	int next,to;
    }edge[maxn*maxn];
    inline void add(int u,int v) {
    	edge[++cnt] = (Edge)<%head[u],v%>;
    	head[u] = cnt;
    }
    bool check(int x,int lx,int y,int ly,int len) {
    	for(int i=0;i<len;++i)
    		if(str[x][lx+i] ^ str[y][ly+i]) return false;
    	return true;
    }
    int Getid(PII x) {
    	return x.fi*N + x.se;
    }
    PII Getpii(int x) {
    	return mp(x/N, x%N);
    }
    void work() {
    	memset(str, 0, sizeof(str));
    	memset(head, 0, sizeof(head)); cnt = 0;
    	memset(f, 0, sizeof(f));
    	n = read();
    	for(int i=1;i<=n;++i) scanf("%s",str[i]+1);
    	for(int i=1;i<=n;++i) {
    		int len = strlen(str[i]+1);
    		for(int j=0;j<=len;++j) {
    			for(int u=1;u<=n;++u) {
    				if(j==0 && i==u) continue;
    				int ulen = strlen(str[u]+1);
    				if(ulen >= len-j) {
    					if(check(i,j+1,u,1,len-j)) {
    						add(Getid(mp(i,j)), Getid(mp(u,len-j)));
    					}
    				} else {
    					if(check(i,j+1,u,1,ulen)) {
    						add(Getid(mp(i,j)), Getid(mp(i,j+ulen)));
    					}
    				}
    			}
    		}
    	}
    	queue<int> q;
    	for(int i=1;i<=n;++i) {
    		int len = strlen(str[i]+1);
    		q.push(Getid(mp(i,0)));
    		f[i][0] = 1;
    	}
    	while(!q.empty()) {
    		int u = q.front(); q.pop();
    		PII uu = Getpii(u); int x = uu.fi, y = uu.se;
    		for(int i=head[u];i;i=edge[i].next) {
    			int v = edge[i].to;
    			PII vv = Getpii(v); int nx = vv.fi, ny = vv.se;
    			if(!f[nx][ny]) {
    				f[nx][ny] = f[x][y]; q.push(v);
    			}
    		}
    	}
    	bool flag = 0;
    	for(int i=1;i<=n;++i) flag |= f[i][strlen(str[i]+1)];
    	if(flag) puts("No");
    	else puts("Yes");
    }
    int main()
    {
    	int T = read();
    	while(T--) work();
    	return 0;
    }
    /*
    1
    2
    00
    000
    
    No
    */
    

    Summary

    可能有一点相似题:[AtCoder Regular Contest 084] D - Small Multiple

  • 相关阅读:
    layDate 只显示 小时&分钟
    获取从今天以后一周的日期列表
    Laravel_$rules参数规则
    Layui——分步表单
    XML命名空间详解
    centos7搭建svn服务器
    jvm原理
    动态代理与反射
    java之JUC
    实现从数据库加载数据并返回easyui-tree所需要数据
  • 原文地址:https://www.cnblogs.com/BaseAI/p/13985212.html
Copyright © 2020-2023  润新知