zoukankan      html  css  js  c++  java
  • CF49E Common ancestor(dp+dp+dp)

    纪念卡常把自己卡死的一次自闭模拟赛

    QWQ
    一开始看这个题,以为是个图论,仔细一想,貌似可以直接dp啊。

    首先,因为规则只有从两个变为1个,貌似可以用类似区间(dp)的方式来(check)一段区间能不能合成某一个字母!

    那我们定义(f[i][j][k])表示第一个串,([l,r])区间,是否可以合成(k)这个字母

    然后转移的时候,枚举区间,枚举规则,枚举断点,满足(f[l][k][p1]==1)(f[k+1][r][p2]==1) 才能使当前状态合法。
    其中(p1,p2)表示当前规则的两个字母

    for (int i=1;i<=n;i++) f[i][i][cc(s[i])]=1; 
      for (register int i=2;i<=n;++i)
        for (register int l=1;l<=n-i+1;++l)
          {
          	 int r = l+i-1;
          	 for (register int j=1;j<=26;++j)
          	 {
          	 	for (register int p=1;p<=num[j];++p)
          	 	{
          	 	  for (register int k=l;k<=r;++k) 
          	 	  {
          	 	    f[l][r][j]=max(f[l][r][j],f[l][k][a[j][p].a]&f[k+1][r][a[j][p].b]);
          	 	    if (f[l][r][j]) break;
          	 	  }
          	 	  if (f[l][r][j]) break;
          	    }
    		 }
    	  }
    

    同时定义(g[l][r][k])数组表示第二个串区间([l,r])能否合成k。处理和f类似。

    统计答案的时候呢
    还需要一个(dp[i][j])表示第一个串的前i个字符和第二个串的前j个字符的最短公共祖先
    那么,考虑枚举两个断点,两个串的后面两段能合成同一个字母,那么就可以从那个断点之前的状态转移过来

    QWQ
    详细直接看代码吧

    memset(dp,127/3,sizeof(dp));
      dp[0][0]=0;
      for (register int i=1;i<=nn;++i)
      {
      	 for (register int k=1;k<=n;++k)
      	 {
      	   for (register int j=1;j<=i;++j)
      	     for (register int p=1;p<=k;++p)
      	     {
      	     	if (dp[j-1][p-1]==dp[maxn-3][maxn-3]) continue;
      	 	    bool flag=false;
      	 	    for (register int o=1;o<=26;o++)
      	 	      if (g[j][i][o] && f[p][k][o]) flag=true;
      	        if (flag) dp[i][k]=min(dp[i][k],dp[j-1][p-1]+1);
      	     }
         }
      }
    

    最后复杂度就是(O(n^4*26))

    我也不知道为啥能跑过啊
    qwqwqwq

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define mk makr_pair
    #define ll long long
    #include<ctime>
    using namespace std;
    inline int read()
    {
      int x=0,f=1;char ch=getchar();
      while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
      while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
      return x*f;
    }
    const int maxn = 110;
    struct Node{
    	int a,b;
    };
    Node a[maxn][maxn];
    int num[maxn];
    int f[maxn][maxn][maxn];
    int g[maxn][maxn][maxn];
    int n,m;
    char s[maxn];
    char ss[maxn];
    int nn;
    string ans;
    int dp[maxn][maxn];
    inline int cc(char c)
    {
    	return c-'a'+1;
    }
    int main()
    {
      scanf("%s",s+1);
      scanf("%s",ss+1);
      s[0]=ss[0]='*';
      n=strlen(s+1);
      nn=strlen(ss+1);  
      m=read();
      for (register int i=1;i<=m;++i)
      {
      	 char ymh[10];
      	 scanf("%s",ymh+1);
      	 int now = ymh[1]-'a'+1;
      	 num[now]++;
      	 a[now][num[now]].a = ymh[4]-'a'+1;
    	 a[now][num[now]].b = ymh[5]-'a'+1; 
      }
      for (int i=1;i<=n;i++) f[i][i][cc(s[i])]=1; 
      for (register int i=2;i<=n;++i)
        for (register int l=1;l<=n-i+1;++l)
          {
          	 int r = l+i-1;
          	 for (register int j=1;j<=26;++j)
          	 {
          	 	for (register int p=1;p<=num[j];++p)
          	 	{
          	 	  for (register int k=l;k<=r;++k) 
          	 	  {
          	 	    f[l][r][j]=max(f[l][r][j],f[l][k][a[j][p].a]&f[k+1][r][a[j][p].b]);
          	 	    if (f[l][r][j]) break;
          	 	  }
          	 	  if (f[l][r][j]) break;
          	    }
    		 }
    	  }
      for (int i=1;i<=nn;i++) g[i][i][cc(ss[i])]=1;
      for (register int i=2;i<=nn;i++)
        for (register int l=1;l<=nn-i+1;++l)
          {
          	 int r = l+i-1;
          	 for (register int j=1;j<=26;++j)
          	 {
          	 	for (register int p=1;p<=num[j];++p)
          	 	{
          	 	  for (register int k=l;k<=r;++k)
    			  { 
          	 	    g[l][r][j]=max(g[l][r][j],g[l][k][a[j][p].a]&g[k+1][r][a[j][p].b]);
          	 	    if (g[l][r][j]) break;
          	 	  }
    			  if (g[l][r][j]) break;
          	    }
    		 }
    	  }
      memset(dp,127/3,sizeof(dp));
      dp[0][0]=0;
      for (register int i=1;i<=nn;++i)
      {
      	 for (register int k=1;k<=n;++k)
      	 {
      	   for (register int j=1;j<=i;++j)
      	     for (register int p=1;p<=k;++p)
      	     {
      	     	if (dp[j-1][p-1]==dp[maxn-3][maxn-3]) continue;
      	 	    bool flag=false;
      	 	    for (register int o=1;o<=26;o++)
      	 	      if (g[j][i][o] && f[p][k][o]) flag=true;
      	        if (flag) dp[i][k]=min(dp[i][k],dp[j-1][p-1]+1);
      	     }
         }
      } 
      if(dp[nn][n]==dp[maxn-3][maxn-3]) dp[nn][n]=-1; 
      cout<<dp[nn][n]<<endl;
      return 0;
    }
    
    
  • 相关阅读:
    将对象转成 json 以及 将字符串 hash(SHA1) 加密
    Model First 开发方式
    DataSet结果转模型类
    Table 类(数据表基类)
    只返回数据表的部分字段(不建类)
    修改数据表部分字段方法封装-及-动态生成对象并动态添加属性
    封装方法:通过方法名调用类内的方法
    同步 VS 异步
    使用 Lambda表达式替换使用 ElemMatch 的方式查询集合类型的字段是否符合某条件
    使用Newtonsoft.Json将数据导出至Json文件
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161976.html
Copyright © 2011-2022 走看看