【动态规划】Codeforces 570E Pig and Palindromes

通道

题意:n*m的字符矩阵,每次只能向右或向下走,求从(1,1)走到(n,m)的路径中有多少个回文。

思路:我们可以从两端开始走。dp[i][j][k]:分别走i步(也可以理解为半径为i),A到达j行,B到达k行的回文数。走的半径逐渐减少即可。

可以知道第x1行只能由前一次的x1行或x1+1行转移,第x2行只能由前一次的x2-1或x2转移,所有就有四种情况。

dp[i][x1][x2] = (dp[i-1][x1][x2] + dp[i-1][x1 + 1][x2] + dp[i-1][x1][x2 - 1] + dp[i-1][x1 + 1][x2 - 1]) % MOD;

代码:

#include <cstdio>
#include <cstring>

typedef long long ll;

const int MAX_N = 507;
const int MOD = 1000000007;

int n, m;
char s[MAX_N][MAX_N];
ll dp[2][MAX_N][MAX_N];

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; ++i)
        scanf("%s", s[i]);
    bool cur = 0;
    int longest = (n + m) / 2 - 1;
    for (int x1 = 0; x1 < n && x1 <= longest; ++x1) {
        int y1 = longest - x1;
        for (int x2 = 0; x2 < n; ++x2) {
            int y2 = m - 1 - (longest - (n - 1 - x2));
            if (x1 <= x2 && y1 <= y2 && s[x1][y1] == s[x2][y2])
                dp[0][x1][x2] = 1;
        }
    }
    for (int i = longest - 1; i >= 0; --i) {
        cur = !cur;
        memset(dp[cur], 0, sizeof dp[cur]);
        for (int x1 = 0; x1 <= i && x1 < n; ++x1) {
            int y1 = i - x1;
            for (int x2 = 0; x2 < n; ++x2) {
                int y2 = m - 1 - (i - (n - 1 - x2));
                if (x1 <= x2 && y1 <= y2 && s[x1][y1] == s[x2][y2])
                    dp[cur][x1][x2] = (dp[!cur][x1][x2] + dp[!cur][x1 + 1][x2] + dp[!cur][x1][x2 - 1] + dp[!cur][x1 + 1][x2 - 1]) % MOD;
            }
        }
    }
    printf("%I64d\n", dp[cur][0][n - 1]);
    return 0;
}

时间: 2024-08-06 18:22:12

【动态规划】Codeforces 570E Pig and Palindromes的相关文章

Codeforces 570E Pig and Palindromes dp

链接 题解链接:点击打开链接 题意: 给定n*m的字母矩阵. 从左上角到右下角的路径中有多少条是回文. 思路: 显然是要从头尾同时dp的,路径1是从左上角到第j行,路径2是从右下角到第k行 dp[i][j][k] 表示路径长度为i,路径1从左上角到第j行,路径2从右下角到第k行,且路径1和2是匹配的方法数. 对于路径1.2合并时要分一下奇偶. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <std

Codeforces #316 E Pig and Palindromes DP

// Codeforces #316 E Pig and Palindromes // // 题目大意: // // 给你一张地图,n*m每个点是一个字母,现在从(0,0)出发, // 每次只能往右或者往下走,求走到(n-1,m-1)形成回文串的方法数. // // 解题思路: // // 动态规划.首先.如果起点和终点的字母不相同,那么肯定 // 不能形成回文串,直接输出0.对于能形成回文串.我们设状态 // d(step,i,j)表示走了step步,从第0行走到i行,第n-1行走到j行的 /

Codeforces Round #316 (Div. 2)E. Pig and Palindromes DP

E. Pig and Palindromes Peppa the Pig was walking and walked into the forest. What a strange coincidence! The forest has the shape of a rectangle, consisting of n rows and m columns. We enumerate the rows of the rectangle from top to bottom with numbe

codeforces 570 E. Pig and Palindromes (DP)

题目链接: 570 E. Pig and Palindromes 题目描述: 有一个n*m的矩阵,每个小格子里面都有一个字母.Peppa the Pig想要从(1,1)到(n, m).因为Peppa the Pig是一个完美主义者,她想要她所经过的路径上的字母组成的字符串是一个回文串,现在Peppa the Pig想要知道有多少满足条件的走法? 解题思路: 因为经过路径上的字母要组成回文串,所以可以从(1,1),(n,m)同时开始dp.从(1,1)出发只能向下方和右方走,从(n,m)出发只能向上

CF 316div2 E.Pig and Palindromes

E. Pig and Palindromes Peppa the Pig was walking and walked into the forest. What a strange coincidence! The forest has the shape of a rectangle, consisting of n rows and m columns. We enumerate the rows of the rectangle from top to bottom with numbe

Codeforces 464A No to Palindromes!(构造)

题目链接:Codeforces 464A No to Palindromes! 题目大意:给定n和m,以及一个字符串s,s不存在长度大于2的回文子串,现在要求输出一个字典比s大的字符串,并 且说同样不存在长度大于2的回文子串. 解题思路:直接去构造即可,从最后一位开始,每次只要考虑该字符是否和前两个字符相同即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std;

codeforces 570 E. Pig and Palindromes

题意:给出n*m的字母表,求从左上角走到右下角能形成多少个回文串,只能往下或往右走. 做法:dp[r1][c1][r2][c2],从左上角走到(r1,c1),从右下角走到(r2,c2)时,能形成多少个回文串,因为爆内存,表示成dp[step][r1][r2],从左上角走到r1行,从右下角走到r2行,分别走了step步时,能形成多少个回文串,因为c1=step+2-r1,c2=n+m-step-r2,所以是一样的,这样差不多能过了,因为两边最多走250步,所以需要的空间是250*500*500,当

【CodeForces】914 E. Palindromes in a Tree 点分治

[题目]E. Palindromes in a Tree [题意]给定一棵树,每个点都有一个a~t的字符,一条路径回文定义为路径上的字符存在一个排列构成回文串,求经过每个点的回文路径数.n<=2*10^5. [算法]点分治 [题解]状压20位的二进制表示一条路径的字符状态,点分治过程中维护扫描过的路径只须维护状态桶数组,t[i]表示前面状态为i的路径条数. 合并:考虑当前状态为j,要使合并的状态满足条件即i^j=1<<k(0<=k<20)或i^j=0,移项得i=j^(1<

codeforces 568a//Primes or Palindromes?// Codeforces Round #315 (Div. 1)

题意:求使pi(n)*q<=rub(n)*p成立的最大的n. 先收集所有的质数和回文数.质数好搜集.回文数奇回文就0-9的数字,然后在头尾添加一个数.在x前后加a,就是x*10+a+a*pow(10,2).偶回文同理.然后不能二分,因为比值不是单调的. 乱码: #pragma comment(linker,"/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include