[SHOI2001]化工厂装箱员(dp?暴力:暴力)

时间:2023-03-08 22:37:19
[SHOI2001]化工厂装箱员(dp?暴力:暴力)

118号工厂是世界唯一秘密提炼锎的化工厂,由于提炼锎的难度非常高,技术不是十分完善,所以工厂生产的锎成品可能会有3种不同的纯度,A:100%,B:1%,C:0.01%,为了出售方便,必须把不同纯度的成品分开装箱,装箱员grant第1次顺序从流水线上取10个成品(如果一共不足10个,则全部取出),以后每一次把手中某种纯度的成品放进相应的箱子,然后再从流水线上顺序取一些成品,使手中保持10个成品(如果把剩下的全部取出不足10个,则全部取出),如果所有的成品都装进了箱子,那么grant的任务就完成了。

由于装箱是件非常累的事情,grant希望他能够以最少的装箱次数来完成他的任务,现在他请你编个程序帮助他。

Solution

写的像个dp似的,感觉其实就是个暴力(考场这么写肯定是打暴力

设dp[i][j][k][l]表示拿到了i个,A有j个,B有j个,C有k个。

大力转移。

注意特判n<10的情况。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int dp[][][][],sum[][],a[],n;
inline void mi(int &a,int b){if(b<a)a=b;}
char s[];
int main(){
scanf("%d",&n);
for(int i=;i<=n;++i){
scanf("%s",s);
a[i]=s[]-'A';
sum[a[i]][i]=sum[a[i]][i-]+;
for(int j=;j<=;++j)if(j!=a[i])sum[j][i]=sum[j][i-];
}
memset(dp,0x3f,sizeof(dp));
if(n<){
cout<<(sum[][n]!=)+(sum[][n]!=)+(sum[][n]!=)<<endl;
return ;
}
dp[][sum[][]][sum[][]][sum[][]]=;
for(int i=;i<=n;++i)
for(int j=;j<=;++j)
for(int k=;k<=&&k+j<=;++k)
for(int l=;l<=&&k+j+l<=;++l)if(dp[i][j][k][l]!=0x3f3f3f3f){
if(j){
int num=j;
mi(dp[min(i+num,n)][sum[][min(n,i+num)]-sum[][i]][k+sum[][min(i+num,n)]-sum[][i]][l+sum[][min(i+num,n)]-sum[][i]],dp[i][j][k][l]+);
}
if(k){
int num=k;
mi(dp[min(i+num,n)][j+sum[][min(n,i+num)]-sum[][i]][sum[][min(n,i+num)]-sum[][i]][l+sum[][min(n,i+num)]-sum[][i]],dp[i][j][k][l]+);
}
if(l){
int num=l;
mi(dp[min(i+num,n)][j+sum[][min(i+num,n)]-sum[][i]][k+sum[][min(i+num,n)]-sum[][i]][sum[][min(i+num,n)]-sum[][i]],dp[i][j][k][l]+);
}
}
int ans=0x3f3f3f3f;
for(int i=;i<=;++i)
for(int j=;i+j<=;++j)
for(int k=;i+j+k<=;++k)if(dp[n][i][j][k]!=0x3f3f3f3f)
ans=min(ans,dp[n][i][j][k]+(i!=)+(j!=)+(k!=));
cout<<ans;;
return ;
}