[BZOJ 1566] 管道取珠
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1566
Solution:
思路十分精奇的一道题目
题目要求的是$\sum_{i=1}^k a_i^2$
明显发现$a_i$是难以求解的,于是考虑如何整体处理$a_i^2$
由于$a_i^2=a_i*a_i$,
因此$a_i^2$可以认为是第一人选出的方案数$a_i$乘上第二人选出的方案数$a_i$
那么只要统计两人选择相同序列的情况数即可
设dp[i][j][k]为取i个字符,两人在上方取到j,k个字符时相同的方案数
接下来再用滚动数组优化下转移就好了
Code:
//by NewErA #include <bits/stdc++.h> using namespace std; const int MOD=1024523; const int MAXN=510; int n,m,dp[2][MAXN][MAXN],up[MAXN],down[MAXN],t=0; char s1[MAXN],s2[MAXN]; int main() { scanf("%d%d",&n,&m); scanf("%s",s1);scanf("%s",s2); for (int i=0;i<n;i++) up[n-i]=s1[i]-'A'; for (int i=0;i<m;i++) down[m-i]=s2[i]-'A'; dp[0][0][0]=1; for(int i=0;i<n+m;i++,t^=1) for(int j=0;j<=min(n,i);j++) for(int k=0;k<=min(n,i);k++) if(dp[t][j][k]) { int temp=dp[t][j][k]; if(j<n && k<n && up[j+1]==up[k+1]) (dp[t^1][j+1][k+1]+=temp)%=MOD; if(j<n && i-k<m && up[j+1]==down[i-k+1]) (dp[t^1][j+1][k]+=temp)%=MOD; if(i-j<m && k<n && down[i-j+1]==up[k+1]) (dp[t^1][j][k+1]+=temp)%=MOD; if(i-j<m && i-k<m && down[i-j+1]==down[i-k+1]) (dp[t^1][j][k]+=temp)%=MOD; dp[t][j][k]=0; } cout << dp[t][n][n]; return 0; }
Review:
1、如果要求解某难以求解之数的多次幂时,
考虑将多次幂转化为降次的其它问题求解
(二次幂转化为两个一次问题的结果相乘)
2、对DP的优化:
如果为同时求解两个同样问题的DP,维护步数和即可,由$O(n^4)$降到$O(n^3)$
如果每次只用到上一层结果,使用滚动数组优化空间