另一个专题。
T1 YATO
将栈的状态作为一棵树来看。
那么每次弹出的操作就是对于当前最左侧的这个元素来说的。
枚举其弹出的时间。
前缀和处理在其之后弹出的元素需要加上的值。
复杂度为
O(Tn3)
代码
#include<bits/stdc++.h>
using namespace std;
#define Komachi is retarded
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)
#define chkmin(a,b) a=min(a,b)
#define chkmax(a,b) a=max(a,b)
#define LL long long
void Rd(int &res){
char c;res=0;
while((c=getchar())<48);
do res=(res<<3)+(res<<1)+(c^48);
while((c=getchar())>47);
}
#define M 104
int T,Case,n,A[M],S[M];
int DP[M][M];
#define INF 0x3f3f3f3f
int DFS(int l,int r){
if(l>=r)return 0;
int &Now=DP[l][r];
if(Now!=INF)return Now;
REP(i,l,r+1)chkmin(Now,(i-l)*A[l]+DFS(l+1,i)+DFS(i+1,r)+(i-l+1)*(S[r]-S[i]));
return Now;
}
int main(){
Rd(T);
while(T--){
Rd(n);REP(i,1,n+1)Rd(A[i]),S[i]=S[i-1]+A[i];
memset(DP,63,sizeof(DP));
printf("Case #%d: %d\n",++Case,DFS(1,n));
}
return 0;
}
T2 SS
期望值显然是每个降落点的概率乘上其到最近大本营的距离。
那么我们就要考虑每个大本营管理的点的位置。
用
Costi,j
表示区间
[i,j]
放一个大本营最小所需的期望。
然后这是一个绝对值函数,取中值即可得到最小。
那么前缀和优化,用一个指针取其位置即可。
剩下的DP应该就比较简单了。
代码
#include<bits/stdc++.h>
using namespace std;
#define Komachi is retarded
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)
#define chkmax(a,b) a=max(a,b)
#define chkmin(a,b) a=min(a,b)
#define DB double
#define M 1004
int n,m;
map<int,DB>V;
int Pos[M];
DB Val[M],Sum[M];
DB F[54][M],Cost[M][M];
int main(){
while(scanf("%d %d",&n,&m)!=EOF){
if(!n)break;
V.clear();
REP(i,0,n){
int L,x;
DB p;
scanf("%d",&L);
while(L--)scanf("%d %lf",&x,&p),V[x]+=p;
}
n=0;
for(map<int,DB>::iterator it=V.begin();it!=V.end();it++)
Pos[++n]=it->first,Val[n]=it->second;
REP(i,1,n+1)Sum[i]=Sum[i-1]+Val[i]*Pos[i],Val[i]+=Val[i-1];
REP(i,1,n+1){
int p=i;
REP(j,i,n+1){
while(p<j && Val[p]<(Val[j]+Val[i-1])/2)p++;
Cost[i][j]=Pos[p]*(Val[p]-Val[i-1])-(Sum[p]-Sum[i-1])
+(Sum[j]-Sum[p])-Pos[p]*(Val[j]-Val[p]);
}
}
REP(i,0,54) REP(j,1,M)F[i][j]=1e15;
REP(i,0,m)F[i][0]=0;
REP(i,0,m) REP(j,1,n+1) REP(k,j,n+1)
chkmin(F[i+1][k],F[i][j-1]+Cost[j][k]);
printf("%.2lf\n",F[m][n]);
}
return 0;
}
T3 E
给出
n
个元素和
显然定义状态
Fi,j
为区间
[i,j]
所得到的答案。
然后考虑如何合并两个区间的结果来得到当前区间的某个划分方案。
如果是运算符是‘+’或‘-’,可知:
区间的答案个数是其长度减一的阶乘。
然后
a1+a2
与
b1+b2+b3
相加后得到的是
3(a1+a2)+2(b1+b2+b3)
。
即阶乘互乘后再相加减。
而运算符为‘*’时,直接相乘即可。
另外,由于左右两侧的操作是可以相互交替进行的,
还需要乘上一个组合数。
代码
#include<bits/stdc++.h>
using namespace std;
#define Komachi is retarded
#define REP(i,a,b) for(int i=(a),i##_end_=(b);i<i##_end_;i++)
#define DREP(i,a,b) for(int i=(a),i##_end_=(b);i>i##_end_;i--)
#define chkmax(a,b) a=max(a,b)
#define chkmin(a,b) a=min(a,b)
#define DB double
#define M 104
#define Mod 1000000007
#define Add(a,b) (a+=b)%=Mod
#define Mul(a,b) (1ll*(a)*(b)%Mod)
int n,Fac[M],F[M][M],G[M][M];
char Op[M];
int Calc(int x,int y,char p){
if(p=='+') return (x+y)%Mod;
if(p=='-') return (x+Mod-y)%Mod;
return Mul(x,y);
}
int main(){
Fac[0]=1;
REP(i,1,M)Fac[i]=Mul(Fac[i-1],i);
REP(i,0,M)G[i][0]=G[0][i]=1;
REP(i,1,M)REP(j,1,M)G[i][j]=(G[i][j-1]+G[i-1][j])%Mod;
while(scanf("%d",&n)!=EOF){
memset(F,0,sizeof(F));
REP(i,1,n+1)scanf("%d",&F[i][i]);
scanf("%s",Op+1);
REP(l,2,n+1)REP(i,1,n-l+2){
int j=i+l-1,q=0,p=l-2;
REP(k,i,j){
Add(F[i][j],Mul(G[q][p],Calc(Mul(Op[k]=='*'?1:Fac[p],F[i][k]),Mul(Op[k]=='*'?1:Fac[q],F[k+1][j]),Op[k])));
q++,p--;
}
}
printf("%d\n",F[1][n]);
}
return 0;
}