[USACO15OPEN]回文的路径Palindromic Paths
[USACO15OPEN]回文的路径Palindromic Paths
题目描述
Farmer John's farm is in the shape of an N \times NN×N grid of fields (1 \le N \le 5001≤N≤500), each labeled with a letter in the alphabet. For example:
ABCD
BXZX
CDXB
WCBA
Each day, Bessie the cow walks from the upper-left field to the lower-right field, each step taking her either one field to the right or one field downward. Bessie keeps track of the string that she generates during this process, built from the letters she walks across. She gets very disoriented, however, if this string is a palindrome (reading the same forward as backward), since she gets confused about which direction she had walked. Please help Bessie determine the number of distinct routes she can take that correspond to palindromes. Different ways of obtaining the same palindrome count multiple times. Please print your answer modulo 1,000,000,007.
农夫FJ的农场是一个N*N的正方形矩阵(2\le N\le 5002≤N≤500),每一块用一个字母作标记。比如说:
ABCD
BXZX
CDXB
WCBA
某一天,FJ从农场的左上角走到右下角,当然啦,每次他只能往右或者往下走一格。FJ把他走过的路径记录下来。现在,请你把他统计一下,所有路径中,回文串的数量(从前往后读和从后往前读一模一样的字符串称为回文串)。
输入输出格式
输入格式:
The first line of input contains NN, and the remaining NN lines contain the
NN rows of the grid of fields. Each row contains NN characters that are
in the range A..Z.
第一行包括一个整数N,表示农场的大小,接下来输入一个N*N的字母矩阵。
输出格式:
Please output the number of distinct palindromic routes Bessie can take,
modulo 1,000,000,007.
输出一个整数,表示回文串的数量。
输入输出样例
4 ABCD BXZX CDXB WCBA
12
说明
Bessie can make the following palindromes
1 x "ABCDCBA"
1 x "ABCWCBA"
6 x "ABXZXBA"
4 x "ABXDXBA"
题解:
貌似以前做过一道类似的题目,也是从左上角和右下角分别开始走,只不过那道题四位动规可以做。(当然数据加强后还是要降维)
首先想到f[i][j][k][l]表示从左上角走到(i,j),从右下角走到(k,l),在路径长度相等的情况下,所经过路径相同的方案数,然后动规方程显而易见。
但是这样做显然会爆时间,考虑降维,实际上只要枚举走过的步数和两个点所在的行数,就可以推出他们的位置,因此f[i][j][k]表示第一个点在第i行,第2个点在第j行,都走了k步的方案数。这样时间复杂度为O(n^3),原题时限2s,高性能评测1s应该没问题。
然后考虑空间,先写出三维状态的转移方程:
f[i][j][k]=(f[i-1][j][k-1]+f[i][j][k-1]+f[i][j+1][k-1]+f[i-1][j+1][k-1])%mod;
很显然步数之和上一层状态有关系,所以可以用滚动数组优化:
f[i][j][now]=(f[i-1][j][pre]+f[i][j][pre]+f[i][j+1][pre]+f[i-1][j+1][pre])%mod;
注:滚动数组开在最后一维,会变快很多,至于为什么,大神说是电脑开内存的方式不一样,具体我也不是很清楚,反正以后把多变的那一维放在后面就可以了。
一下是AC代码:
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #define mod (1000000007) using namespace std; typedef long long lol; lol f[502][502][2],ans,n,now,pre; char map[502][502]; lol gi() { lol ans=0,f=1; char i=getchar(); while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();} while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} return ans*f; } int main() { lol i,j,k; n=gi(); for(i=1;i<=n;i++) scanf("%s",map[i]+1); now=1;pre=0; if(map[1][1]!=map[n][n]){printf("0\n");return 0;} else f[1][n][pre]=1; for(k=2;k<=n;k++) { for(i=1;i<=n;i++) { if(i>k)break; for(j=n;j>=i;j--) { if(n-j+1>k)break; if(map[i][k-i+1]==map[j][n-k+n-j+1]) f[i][j][now]=(f[i-1][j][pre]+f[i][j][pre]+f[i][j+1][pre]+f[i-1][j+1][pre])%mod; else f[i][j][now]=0; } } swap(now,pre); } for(i=1;i<=n;i++) { ans=(ans+f[i][i][pre])%mod; } printf("%lld",ans); return 0; }