超级码力在线编程大赛初赛 第1场 T4.对称前后缀【字符串/区间DP】

题目链接https://tianchi.aliyun.com/oj/14491652514320995/73733636160164531

思路

用dp[j][i]表示[j,i]区间内的最长对称前后缀的一半(区间长度为奇数则不算中间那个数)。
转移方程: d p [ j ] [ i ] = d p [ j + 1 ] [ i − 1 ] + 1 dp[j][i]=dp[j+1][i-1]+1 dp[j][i]=dp[j+1][i1]+1

考虑两种情况:
①[j,i]区间内最长对称前后缀重合。
例如aba,此时dp[0][2]=1,对于[0,2]区间,ans+=2*dp[0][2]+1。
例如abba,此时dp[1][2]=1,dp[0][3]=2,对于[0,3]区间,ans+=2*dp[0][3]。
②[j,i]区间内最长对称前后缀被隔断(无法重合)。
例如abca,此时dp[0][3]=1,对于[0,3]区间,ans+=dp[0][3]。

方便本地调试的代码

#include <bits/stdc++.h>
using namespace std;
const int N=3e3+10;
int dp[N][N];
int main()
{
    
    

    string s;
    cin>>s;
    int sz=s.length();
    long long ans=(long long)sz;
    vector<int>g[26];
    memset(dp,0,sizeof(dp));
    for(int i=0;i<26;i++)
        g[i].clear();
    for(int i=0;i<sz;i++)
    {
    
    
        int x=s[i]-'a';
        g[x].push_back(i); // g[x]保存字母x的所有位置
        int n=(int)g[x].size();
        if(n>1)
        {
    
    
            for(int k=0;k<n-1;k++)
            {
    
    
                int j=g[x][k]; // j <- i
                int d=i-j+1;
                dp[j][i]=dp[j+1][i-1]+1;
                ans+=dp[j][i];
                if(d%2==1&&dp[j][i]*2+1==d)ans+=dp[j][i]+1; // 例如:aba
                else if(d%2==0&&dp[j][i]*2==d)ans+=dp[j][i]; // 例如:abba
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}
/*
aba
ans:6

abba
ans:10

aa
ans:4

aaa
ans:10

aaaa
ans:20

bacbdab
ans:12

abcca
ans:8

abcc
ans:6

bdcabcd
ans:11

abccbac
ans:21
*/

最终提交的代码

const int N=3e3+10;
int dp[N][N];
class Solution {
    
    
public:
    /**
     * @param s: a string.
     * @return: return the values of all the intervals.
     */
    long long suffixQuery(string &s) {
    
    
        int sz=s.length();
        long long ans=(long long)sz;
        vector<int>g[26];
        memset(dp,0,sizeof(dp)); // 一定要初始化!否则wa!
        for(int i=0;i<26;i++)
            g[i].clear();
        for(int i=0;i<sz;i++)
        {
    
    
            int x=s[i]-'a';
            g[x].push_back(i); // g[x]保存字母x的所有位置
            int n=(int)g[x].size();
            if(n>1)
            {
    
    
                for(int k=0;k<n-1;k++)
                {
    
    
                    int j=g[x][k]; // j <- i
                    int d=i-j+1;
                    dp[j][i]=dp[j+1][i-1]+1;
                    ans+=dp[j][i];
                    if(d%2==1&&dp[j][i]*2+1==d)ans+=dp[j][i]+1; // 例如:aba
                    else if(d%2==0&&dp[j][i]*2==d)ans+=dp[j][i]; // 例如:abba
                }
            }
        }
        return ans; 
    }
};

(class中dp数组没有memset,wa了无数次)

猜你喜欢

转载自blog.csdn.net/ljw_study_in_CSDN/article/details/108296909
今日推荐