Codeforces Round #510 #B

http://codeforces.com/contest/1042/problem/B

题意:

给出n种饮料,每种饮料还有一种或多种维生素(A或B或C),某人想集齐三种维生素,问最少需要花费多少?

每一行先输入每种饮料的价格,再输入每种饮料的包含的维生素种类。

将ABC分别用一个数字表示,开始时准备:1表示A,2表示B,3表示C。

包含维生素A的饮料=1,包含维生素B的=2,C=3,AB=A+B=3,到了这就发现这样不对,有重复了。

所以我们最好用三个质数表示ABC。

这里A=2,B=5,C=11。

AB=A*B=10,AC=A*C=22,BC=B*C=55;

ABC=110.

当然这里用加表示也可以,看心情啦。

那么我们需要在输入时,记录每种饮料的还费最小值,并且判断三种维生素是否都出现过。

那么我们的答案就是$$min { AB+C,AC+B,BC+A,A+B+C,AC+BC,AB+BC,AB+AC }$$

当然判断答案时你需要判断这种饮料是否出现过。

!!!越离奇的方法越不容易被hack。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int p[100000],ans,cnt;
int n,val[1006],cost,a[222];        //A=2,B=5,C=11;
char s[4];
bool vis[1100],hack[100000];        //hack数组判断某种饮料是否出现过。 
int main()
{
    ans=2147483647;
    a['A']=2;a['B']=5;a['C']=11;
    memset(p,0x7f,sizeof(p));
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&cost);
        scanf("%s",s);
        int l=strlen(s),tot=1;
        for(int j=0; j<l; j++)
        {
            tot*=a[s[j]];
            if(!vis[s[j]])vis[s[j]]=1,cnt++;
        }
        p[tot]=min(p[tot],cost);
        hack[tot]=1;
    }
    if(cnt<3)printf("-1");
    else
    {
        
        if(hack[2]&&hack[5]&&hack[11])ans=min(ans,p[2]+p[5]+p[11]);
        if(hack[10]&&hack[11])ans=min(ans,p[10]+p[11]);
        if(hack[22]&&hack[5])ans=min(ans,p[22]+p[5]);
        if(hack[55]&&hack[2])ans=min(ans,p[55]+p[2]);
        if(hack[110])ans=min(ans,p[110]);
        if(hack[10]&&hack[55])ans=min(ans,p[10]+p[55]);
        if(hack[22]&&hack[55])ans=min(ans,p[22]+p[55]);
        if(hack[10]&&hack[22])ans=min(ans,p[10]+p[22]);
        printf("%d",ans);
    }

}
原文地址:https://www.cnblogs.com/rmy020718/p/9667668.html