多边形:https://www.acwing.com/problem/content/285/
其实就是环形的石子合并,只不过由于乘法的存在还要记录一下最大值与最小值。
AC代码:
cpp
#include <bits/stdc++.h>
using namespace std;
int a[105];
char b[105];
int dpmax[105][105];
int dpmin[105][105];
int main()
{
int n;
int ret = 0;
scanf("%d",&n);
for(int i = 1; i <= 2*n; ++i) {
if(i % 2 == 1) {
cin>>b[(i/2)+1];
b[(i/2)+1+n] = b[(i/2)+1];
}
if(i % 2 == 0) {
cin>>a[i/2];
a[i/2+n] = a[i/2];
}
}
memset(dpmax,0xc0,sizeof(dpmax));
memset(dpmin,0x3f,sizeof(dpmin));
for(int i = 1; i <= 2*n; ++i) {
dpmax[i][i] = a[i];
dpmin[i][i] = a[i];
}
for(int len = 1; len <= n; ++len)
for(int l = 1; l + len <= 2*n; ++l) {
int r = l + len;
for(int k = l; k < r; ++k) {
if(b[k+1] == 't') {
dpmax[l][r] = max(dpmax[l][r],dpmax[l][k] + dpmax[k+1][r]);
dpmin[l][r] = min(dpmin[l][r],dpmin[l][k] + dpmin[k+1][r]);
} else {
dpmax[l][r] = max(dpmax[l][r],dpmax[l][k]*dpmax[k+1][r]);
dpmax[l][r] = max(dpmax[l][r],dpmin[l][k]*dpmin[k+1][r]);
dpmin[l][r] = min(dpmin[l][r],dpmin[l][k]*dpmin[k+1][r]);
dpmin[l][r] = min(dpmin[l][r],dpmax[l][k]*dpmin[k+1][r]);
dpmin[l][r] = min(dpmin[l][r],dpmin[l][k]*dpmax[k+1][r]);
}
}
}
for(int i = 1; i <= n; ++i) ret = max(ret,dpmax[i][i+n-1]);
printf("%d\n",ret);
for(int i = 1; i <= n; ++i)
if(dpmax[i][i+n-1] == ret) printf("%d ",i);
}
金字塔:https://www.acwing.com/problem/content/286/
显然,我们令表示DFS序列为区间的树的集合(由DFS知道连续的)
下面是状态的计算,我们以最右的子树为划分即可。
怎么划分?我们先固定最右一点,向左找与r相同的边界k()(非空)同时k属于偶数(由DFS序性质)。用乘法原理相乘即可:。
AC代码:
cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=1e9;
string s;
ll dp[330][330];
int main(){
cin>>s;
int n=s.size();
if(n%2==0) cout<<0<<endl;
else{
for(int len=1;len<=n;len+=2){
for(int l=0;l+len-1<n;l++){
int r=l+len-1;
if(len==1) dp[l][l]=1;
else if(s[l]==s[r]){
for(int k=l;k<r;k+=2){
if(s[k]==s[r]){
dp[l][r]=(dp[l][r]+dp[l][k]*dp[k+1][r-1]%mod)%mod;
}
}
}
}
}
cout<<dp[0][n-1];
}
}