P1220 关路灯
- 参考《算法竞赛入门经典 ( S e c o n d E d i t i o n ) P 293 U V a 1336 (Second\ Edition)\ P293 \ UVa1336 (Second Edition) P293 UVa1336》
- 在任意时刻,已关的灯一定是一个连续的区间
- f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示关上了灯 [ i , j ] [i,j] [i,j],且当前位置在 k k k, k = 0 k=0 k=0表示在左端点i, k = 1 k=1 k=1表示在右端点j
- f [ i ] [ j ] [ 0 ] = m i n ( f [ i + 1 ] [ j ] [ 0 ] + ( p o s [ i + 1 ] − p o s [ i ] ) ∗ ( s u m [ i ] + s u m [ n ] − s u m [ j ] ) , f [ i + 1 ] [ j ] [ 1 ] + ( a [ j ] − a [ i ] ) ∗ ( s u m [ i ] + s u m [ n ] − s u m [ j ] ) ) ; f[i][j][0] = min ( f[i+1][j][0] + ( pos[i+1] - pos[i] ) * ( sum[i] + sum[n] - sum[j] ) , f[i+1][j][1] + ( a[j]-a[i] ) * ( sum[i]+sum[n]-sum[j]) ); f[i][j][0]=min(f[i+1][j][0]+(pos[i+1]−pos[i])∗(sum[i]+sum[n]−sum[j]),f[i+1][j][1]+(a[j]−a[i])∗(sum[i]+sum[n]−sum[j]));
- f [ i ] [ j ] [ 1 ] = m i n ( f [ i ] [ j − 1 ] [ 0 ] + ( p o s [ j ] − p o s [ i ] ) ∗ ( s u m [ i − 1 ] + s u m [ n ] − s u m [ j − 1 ] ) , f [ i ] [ j − 1 ] [ 1 ] + ( a [ j ] − a [ j − 1 ] ) ∗ ( s u m [ i − 1 ] + s u m [ n ] − s u m [ j − 1 ] ) ) ; f[i][j][1] = min ( f[i][j-1][0] + ( pos[j] - pos[i] ) * ( sum[i-1] + sum[n] - sum[j-1] ) , f[i][j-1][1] + ( a[j]-a[j-1] ) * ( sum[i-1] + sum[n] - sum[j-1] ) ); f[i][j][1]=min(f[i][j−1][0]+(pos[j]−pos[i])∗(sum[i−1]+sum[n]−sum[j−1]),f[i][j−1][1]+(a[j]−a[j−1])∗(sum[i−1]+sum[n]−sum[j−1]));
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,c,f[60][60][2],sum[60],inf=1e7;
struct lamp{
int p,c;
}s[60];
int main(){
cin>>n>>c;
for(int i=1;i<=n;i++){
cin>>s[i].p>>s[i].c;
sum[i]=sum[i-1]+s[i].c;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j][0]=f[i][j][1]=inf;
}
}
f[c][c][0]=f[c][c][1]=0;
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
f[i][j][0]=min(f[i+1][j][0]+(s[i+1].p-s[i].p)*(sum[n]-(sum[j]-sum[i])),
f[i+1][j][1]+(s[j].p-s[i].p)*(sum[n]-(sum[j]-sum[i])));
f[i][j][1]=min(f[i][j-1][0]+(s[j].p-s[i].p)*(sum[n]-(sum[j-1]-sum[i-1])),
f[i][j-1][1]+(s[j].p-s[j-1].p)*(sum[n]-(sum[j-1]-sum[i-1])));
}
}
cout<<min(f[1][n][0],f[1][n][1])<<endl;
}
P3205 [HNOI2010]合唱队
- f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示区间 [ i , j ] [i,j] [i,j]的方案数,当 k = 0 k=0 k=0时表示从左边加入,当 k = 1 k=1 k=1时表示从右边加入。
- f [ i ] [ j ] [ 0 ] + = f [ i + 1 ] [ j ] [ 0 ] , h [ i ] < h [ i + 1 ] f[i][j][0]+=f[i+1][j][0],h[i]<h[i+1] f[i][j][0]+=f[i+1][j][0],h[i]<h[i+1]
- f [ i ] [ j ] [ 0 ] + = f [ i + 1 ] [ j ] [ 1 ] , h [ i ] < h [ j ] f[i][j][0]+=f[i+1][j][1],h[i]<h[j] f[i][j][0]+=f[i+1][j][1],h[i]<h[j]
- f [ i ] [ j ] [ 1 ] + = f [ i ] [ j − 1 ] [ 0 ] , h [ j ] > h [ i ] f[i][j][1]+=f[i][j-1][0],h[j]>h[i] f[i][j][1]+=f[i][j−1][0],h[j]>h[i]
- f [ i ] [ j ] [ 1 ] + = f [ i ] [ j − 1 ] [ 1 ] , h [ j ] > h [ j − 1 ] f[i][j][1]+=f[i][j-1][1],h[j]>h[j-1] f[i][j][1]+=f[i][j−1][1],h[j]>h[j−1]
- 只有一个人时方案只有一种,默认从左边加入,初始化时 f [ i ] [ i ] [ 0 ] = 1 f[i][i][0]=1 f[i][i][0]=1
#include<iostream>
#include<algorithm>
using namespace std;
int n,h[1010],mod=19650827,f[1010][1010][2];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>h[i];
f[i][i][0]=1;
}
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
if(h[i]<h[i+1]) f[i][j][0]+=f[i+1][j][0];
if(h[i]<h[j]) f[i][j][0]+=f[i+1][j][1];
if(h[j]>h[j-1]) f[i][j][1]+=f[i][j-1][1];
if(h[j]>h[i]) f[i][j][1]+=f[i][j-1][0];
f[i][j][0]%=mod;f[i][j][1]%=mod;
}
}
cout<<(f[1][n][0]+f[1][n][1])%mod<<endl;
}
P1880 [NOI1995]石子合并
- 拆环为链
- f [ i ] [ j ] f[i][j] f[i][j]表示区间 [ i , j ] [i,j] [i,j]的最大得分, g [ i ] [ j ] g[i][j] g[i][j]表示区间 [ i , j ] [i,j] [i,j]的最小得分
- f [ i ] [ j ] = s u m [ i ] [ j ] + m a x ( f [ i ] [ k ] + f [ k + 1 ] [ j ] ) , i ≤ k < j f[i][j]=sum[i][j]+max(f[i][k]+f[k+1][j]),i\leq k<j f[i][j]=sum[i][j]+max(f[i][k]+f[k+1][j]),i≤k<j
- g [ i ] [ j ] = s u m [ i ] [ j ] + m i n ( g [ i ] [ k ] + g [ k + 1 ] [ j ] ) , i ≤ k < j g[i][j]=sum[i][j]+min(g[i][k]+g[k+1][j]),i\leq k<j g[i][j]=sum[i][j]+min(g[i][k]+g[k+1][j]),i≤k<j
#include<iostream>
#include<algorithm>
using namespace std;
int n,a[210],sum[210],f[210][210],g[210][210],inf=1e9,maxans,minans=inf;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[n+i]=a[i];
}
for(int i=1;i<=2*n-1;i++){
sum[i]=sum[i-1]+a[i];
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=2*n-1;i++){
int j=i+len-1;
g[i][j]=inf;
for(int k=i;k<j;k++){
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]+sum[j]-sum[i-1]);
}
}
}
for(int i=1;i<=n;i++){
maxans=max(maxans,f[i][i+n-1]);
minans=min(minans,g[i][i+n-1]);
}
cout<<minans<<endl<<maxans<<endl;
}
P1063 能量项链
- f [ i ] [ j ] = h e a d [ i ] ∗ h e a d [ k + 1 ] ∗ h e a d [ j ] + m a x ( f [ i ] [ k ] + f [ k + 1 ] [ j ] ) f[i][j]=head[i]*head[k+1]*head[j]+max(f[i][k]+f[k+1][j]) f[i][j]=head[i]∗head[k+1]∗head[j]+max(f[i][k]+f[k+1][j])
#include<iostream>
#include<algorithm>
using namespace std;
int head[300],f[300][300];
int n,ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>head[i];
head[n+i]=head[i];
}
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=2*n-1;i++){
int j=i+len-1;
for(int k=i;k<j;k++){
f[i][j]=max(f[i][j],head[i]*head[k+1]*head[j+1]+f[i][k]+f[k+1][j]);
}
ans=max(ans,f[i][j]);
}
}
cout<<ans<<endl;
}
P1005 矩阵取数游戏(60分)
- 每一行是独立的,单独求每一行的最大求和即可。
- d p [ i ] [ j ] dp[i][j] dp[i][j]表示区间 [ i , j ] [i,j] [i,j]尚未被选择的最大值
- d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] + 2 m − ( j − i ) + 1 ∗ a [ i − 1 ] , d p [ i ] [ j + 1 ] ∗ 2 m − ( j − i ) + 1 ∗ a [ j + 1 ] ) dp[i][j]=max(dp[i-1][j]+2^{m-(j-i)+1}*a[i-1],dp[i][j+1]*2^{m-(j-i)+1}*a[j+1]) dp[i][j]=max(dp[i−1][j]+2m−(j−i)+1∗a[i−1],dp[i][j+1]∗2m−(j−i)+1∗a[j+1])
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,a[90];
long long dp[90][90],sum,ans;
long long quick_pow(long long a,long long x){
long long ans=1;
while(x){
if(x&1) ans=ans*a;
a=a*a;
x>>=1;
}
return ans;
}
int main(){
cin>>n>>m;
while(n--){
memset(dp,0,sizeof dp);
ans=0;
for(int i=1;i<=m;i++) cin>>a[i];
for(int i=1;i<=m;i++){
for(int j=m;j>=i;j--){
long long x=quick_pow(2,m-(j-i)-1);
dp[i][j]=max(dp[i][j],max(dp[i-1][j]+x*a[i-1],dp[i][j+1]+x*a[j+1]));
}
}
for(int i=1;i<=m;i++){
ans=max(ans,dp[i][i]+quick_pow(2,m)*a[i]);
}
sum+=ans;
}
cout<<sum<<endl;
}
P3146 [USACO16OPEN]248 G
- f [ i ] [ j ] f[i][j] f[i][j]表示区间 [ i , j ] [i,j] [i,j]中的元素全部合并所得到的最大数值
#include<iostream>
#include<algorithm>
using namespace std;
int n,a[250],f[250][250],ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];f[i][i]=a[i];
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<j;k++){
if(f[i][k]==f[k+1][j]){
f[i][j]=max(f[i][j],f[i][k]+1);
ans=max(ans,f[i][j]);
}
}
}
}
cout<<ans<<endl;
}
P4170 [CQOI2007]涂色
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示区间
[
i
,
j
]
[i,j]
[i,j]的最少涂色次数
f
[
i
]
[
j
]
=
{
1
,
i
=
=
j
m
i
n
(
f
[
i
+
1
]
[
j
]
,
f
[
i
]
[
j
−
1
]
,
s
[
i
]
=
=
s
[
j
]
m
i
n
(
f
[
i
]
[
k
]
+
f
[
k
+
1
]
[
j
]
)
,
k
∈
[
i
,
j
−
1
]
,
s
[
i
]
≠
s
[
j
]
f[i][j]=\left\{ \begin{aligned} 1,i==j\\ min(f[i+1][j],f[i][j-1],s[i]==s[j] \\ min(f[i][k]+f[k+1][j]),k\in[i,j-1],s[i]\neq s[j] \end{aligned} \right.
f[i][j]=⎩⎪⎨⎪⎧1,i==jmin(f[i+1][j],f[i][j−1],s[i]==s[j]min(f[i][k]+f[k+1][j]),k∈[i,j−1],s[i]=s[j]
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
string s;
int n,f[60][60],inf=1e9;
int main(){
cin>>s;n=s.length();s.insert(0," ");
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=inf;
}
}
for(int i=1;i<=n;i++){
f[i][i]=1;
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
if(s[i]==s[j]) f[i][j]=min(f[i+1][j],f[i][j-1]);
else{
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
}
}
cout<<f[1][n]<<endl;
}
CF607B Zuma
- f [ i ] [ j ] f[i][j] f[i][j]表示区间 [ i , j ] [i,j] [i,j]的最少合并时间
- f [ i ] [ j ] = { f [ i + 1 ] [ j − 1 ] , a [ i ] = = a [ j ] m i n ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] ) f[i][j]=\left\{ \begin{aligned} f[i+1][j-1],a[i]==a[j]\\ min(f[i][j],f[i][k]+f[k+1][j]) \end{aligned} \right. f[i][j]={f[i+1][j−1],a[i]==a[j]min(f[i][j],f[i][k]+f[k+1][j])
- 初始化 f [ i ] [ i ] = 1 f[i][i]=1 f[i][i]=1, f [ i ] [ i + 1 ] = { 1 , a [ i ] = = a [ i + 1 ] 2 , a [ i ] ≠ a [ i + 1 ] f[i][i+1]=\left\{ \begin{aligned} 1,a[i]==a[i+1]\\ 2,a[i]\neq a[i+1] \end{aligned} \right. f[i][i+1]={1,a[i]==a[i+1]2,a[i]=a[i+1]
#include<iostream>
#include<algorithm>
using namespace std;
int n,a[600],f[600][600],inf=2e9;
void init(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=inf;
}
}
for(int i=1;i<=n;i++){
f[i][i]=1;
}
for(int i=1;i<n;i++){
if(a[i]==a[i+1]) f[i][i+1]=1;
else f[i][i+1]=2;
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
init();
for(int len=3;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
if(a[i]==a[j]) f[i][j]=f[i+1][j-1];
for(int k=i;k<j;k++)
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
}
}
cout<<f[1][n]<<endl;
}