P2466 Sue 的小球
1.对于一个区间 (l,r) ,我们得到了最优解,再往外转移必定是最优的,然后就能将求区间最优转化为子问题递归求解。
2.那么一个一个彩蛋收集,此时 Sue 就有 4 种情况:
对于 l−1 这个彩蛋, Sue 可以从 l 或 r 过去收集。
对于 r+1 这个彩蛋, Sue 可以从 l 或 r 过去收集。
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1010;
struct node{
int x,y,v;
bool operator < (node b) const {
return x<b.x;
}
}a[N];
int n,x0,ans,f[N][N][2];
signed main(){
cin>>n>>x0;
a[n+1].x=x0;
memset(f,0x3f3f3f3f,sizeof(f));
for(int i=1;i<=n;i++)
scanf("%lld",&a[i].x);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i].y),ans+=a[i].y;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i].v);
n++;
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
if(a[i].x==x0){
f[i][i][0]=f[i][i][1]=0;
break;
}
for(int i=1;i<=n;i++)
a[i].v+=a[i-1].v;
for(int i=1;i<=n;i++)
for(int l=1,r=l+i;r<=n;l++,r++){
f[l][r][0]=min(f[l+1][r][0]+(a[l+1].x-a[l].x)*(a[l].v+a[n].v-a[r].v),
f[l+1][r][1]+(a[r].x-a[l].x)*(a[l].v+a[n].v-a[r].v));
f[l][r][1]=min(f[l][r-1][0]+(a[r].x-a[l].x)*(a[l-1].v+a[n].v-a[r-1].v),
f[l][r-1][1]+(a[r].x-a[r-1].x)*(a[l-1].v+a[n].v-a[r-1].v));
}
printf("%.3lf\n",(ans-min(f[1][n][0],f[1][n][1]))/1000.0);
return 0;
}
P7914 括号序列
1.设 f[l,r] 区间 [l,r] 可以形成多少合法串。根据题目条件得知合法串两边都必须是括号,且左边一定是左括号,右边一定是右括号。
2.第一种 (S)(S) 的情况,直接扫一遍 O(n)O(n)。然后考虑 (A),(SA),(AS)。第一种从 [l+1,r−1] 转移,剩下的扫一遍,从 f[i+1,r−1],f[l+1,i−1] ,其中 s[l+1,i],s[i,r−1] 是 S,转移,复杂度 O(n)。
最后一种考虑枚举断点,转移方程大概是 f[l,i]×f[j,r],s[i+1,j−1] 是 S。随便前后缀和优化一些也可以做到 O(n)。
但是这样会算重,考虑 (∗∗)()∗(),会在每个断点处算一次,那么根据套路,直接让他在第一个断点被计算。
3.考虑给 dp 加一维状态,f[i,j,0/1] 分别代表能或不能使用最后一种转移,那么 f[l,i,0]×f[j,r,1] 转移即可。
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int N=5e2+5;
int n,k,dp[N][N][3],d[N];
char s[N];
signed main(){
scanf("%lld %lld",&n,&k);
scanf("%s",s+1);
for(register int i=1;i<=n;i++){
d[i]=d[i-1];
if((s[i]=='('||s[i]=='?')&&(s[i+1]==')'||s[i+1]=='?')) dp[i][i+1][0]=1;
if(s[i]=='('||s[i]==')') d[i]=d[i-1]+1;
}
for(register int i=2;i<=n;i++){
for(register int l=1;l<=n;l++){
int r=l+i-1;
if(r>n) break;
if(r-l>=2&&(s[l]=='('||s[l]=='?')&&(s[r]==')'||s[r]=='?')){
dp[l][r][0]=((dp[l][r][0]+dp[l+1][r-1][1])%mod+dp[l+1][r-1][0])%mod;
}
if(r-l>=2&&((d[r-1]-d[l])==0)&&(s[l]=='('||s[l]=='?')&&(s[r]==')'||s[r]=='?')&&r-l-1<=k){
dp[l][r][0]=(dp[l][r][0]+((d[r-1]-d[l])==0))%mod;
}
if(r-l>=3){
for(register int p=l;p<r;p++){
dp[l][r][1]=((dp[l][p][0]%mod*(dp[p+1][r][0]+dp[p+1][r][1])%mod)%mod+dp[l][r][1])%mod;
}
}
if(r-l>=4&&(s[l]=='('||s[l]=='?')&&(s[r]==')'||s[r]=='?')){
for(register int p=r-k-1;p<r-1;p++){
if(r-p-1<=k) dp[l][r][0]=(dp[l][r][0]+(dp[l+1][p][0]+dp[l+1][p][1])*((d[r-1]-d[p])==0))%mod;
}
}
if(r-l>=4&&(s[l]=='('||s[l]=='?')&&(s[r]==')'||s[r]=='?')){
for(register int p=l+1;p<=min(l+k,r-1);p++){
if(p-l<=k) dp[l][r][0]=(dp[l][r][0]+(dp[p+1][r-1][0]+dp[p+1][r-1][1])*((d[p]-d[l])==0))%mod;
}
}
if(r-l>=2){
for(register int p=l;p<=min(l+k-1,r);p++){
dp[l][r][2]=(dp[l][r][2]+(dp[p+1][r][0]+dp[p+1][r][1])%mod*((d[p]-d[l-1])==0))%mod;
}
}
if(r-l>=4){
for(register int p=l+1;p<r-1;p++){
dp[l][r][1]=(dp[l][r][1]+(dp[l][p][0]%mod*dp[p+1][r][2]%mod)%mod)%mod;
}
}
}
}
printf("%lld",(dp[1][n][0]+dp[1][n][1])%mod);
}