codeforces 789E. The Great Mixing(想法,图论/bitset+dp)

题目链接

E. The Great Mixing
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Sasha and Kolya decided to get drunk with Coke, again. This time they have k types of Coke. i-th type is characterised by its carbon dioxide concentration . Today, on the party in honour of Sergiy of Vancouver they decided to prepare a glass of Coke with carbon dioxide concentration . The drink should also be tasty, so the glass can contain only integer number of liters of each Coke type (some types can be not presented in the glass). Also, they want to minimize the total volume of Coke in the glass.

Carbon dioxide concentration is defined as the volume of carbone dioxide in the Coke divided by the total volume of Coke. When you mix two Cokes, the volume of carbon dioxide sums up, and the total volume of Coke sums up as well.

Help them, find the minimal natural number of liters needed to create a glass with carbon dioxide concentration . Assume that the friends have unlimited amount of each Coke type.

Input
The first line contains two integers n, k (0 ≤ n ≤ 1000, 1 ≤ k ≤ 106) — carbon dioxide concentration the friends want and the number of Coke types.

The second line contains k integers a1, a2, ..., ak (0 ≤ ai ≤ 1000) — carbon dioxide concentration of each type of Coke. Some Coke types can have same concentration.

Output
Print the minimal natural number of liter needed to prepare a glass with carbon dioxide concentration , or -1 if it is impossible.

Examples
input
400 4
100 300 450 500
output
2
input
50 2
100 25
output
3
Note
In the first sample case, we can achieve concentration using one liter of Coke of types and : .

In the second case, we can achieve concentration using two liters of type and one liter of type:

题意:要求浓度为 \(\frac{n}{1000}\) 的coke,你现在有 \(k\) 种,浓度分别为 \(\frac{a[i]}{1000}\),每种可以任意选多少,问你最少需要多少升,如果不能调制则输出-1。

题解:假设需要 \(s_1,s_2,…,s_m\)

那么\(\frac{s_1+s_2+...+s_m}{1000 \times m}=\frac{n}{1000}\)

\(s_1+s_2+…+s_m=n \times m\)

\((s_1-n)+(s_2-n)+…+(s_m-n)=0\).

那么,像相当于在 \(k\) 种数中选出最少个数个组成0.首先可以证明这些数的个数最大为1000,因为假设目标浓度为b,有小于b的浓度a,大于b的浓度c。我们只需要 \(c-b\)\(a\)\(b-a\)\(c\) 就能配成 \(b\). \(\frac{(c-b)*a+(b-a)*c}{(c-b)+(b-a)}=b\),此时我们用了\((c-b)+(b-a)=a-c\) 升,最大就是 \(1000\)了.有两种解决方法:

1.将 \([-1000,1000]\) 内的每个数当成点,\(a_i-n\) 当作边,那么就相当于从0开始最少多少步能够走回0,最短路求即可。

2.考虑dp,不过需要 \(bitset\) 优化,\(d[i]\) 表示进行 \(i\) 次操作能到达的组成的数,\(i\) 最多1000,由于会产生负数要整体移位。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<endl;
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=1e9;
const ll mod=1000000007;
const int maxn=1000+10;
int a[maxn];

int head[maxn*2];
struct edge
{
    int to,next;
}e[maxn*maxn*2];   //
int tol=0;
void add(int u,int v)
{
    e[++tol].to=v,e[tol].next=head[u],head[u]=tol;
}
int d[maxn*2],inq[maxn*2],q[maxn*2];
int mx=0,mi=1e9;
void spfa(int s)
{
    rep(i,mi,mx+1) d[i]=inf;
    int front=0,rear=0;
    for(int i=head[s];i;i=e[i].next)
    {
        int v=e[i].to;
        d[v]=0;
        inq[v]=1;
        q[rear++]=v;
    }
    while(front!=rear)
    {
        int u=q[front++];
        if(front>=maxn*2) front=0;
        inq[u]=0;
        for(int i=head[u];i;i=e[i].next)
        {
            int v=e[i].to;
            if(d[v]>d[u]+1)
            {
                d[v]=d[u]+1;
                if(inq[v]) continue;
                inq[v]=1;
                q[rear++]=v;
                if(rear>=maxn*2) rear=0;
            }
        }
    }
}

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    memset(head,0,sizeof(head));
    tol=0;
    
    rep(i,1,k+1)
    {
        int v;
        scanf("%d",&v);
        a[v]=1;
        mx=max(mx,v);
        mi=min(mi,v);
    }
    if(mi>n||mx<n) return 0*puts("-1");
    rep(i,mi,mx+1)
    {
        rep(j,0,maxn)
        {
            if(a[j])
            {
                int t=i+j-n;
                if(t<mi||t>mx) continue;
                add(i,t);
               // dbg(i);dbg(t);
            }
        }
    }
    spfa(n);
    printf("%d\n",d[n]+1);
    return 0;
}
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
#define dbg(...) cerr<<"["<<#__VA_ARGS__":"<<(__VA_ARGS__)<<"]"<<endl;
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=1000+10;

int a[maxn];
bitset<maxn*2> d[2];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    int mi=inf,mx=0;
    rep(i,1,k+1)
    {
        int v;
        scanf("%d",&v);
        mx=max(mx,v);
        mi=min(mi,v);
        a[v]=1;
        if(v==n) return 0*puts("1");
    }
    if(mx<n||mi>n) return 0*puts("-1");
    int cur=0;
    d[0][n]=1;
    rep(i,1,maxn)
    {
        cur^=1;
        d[cur].reset();
        rep(j,0,maxn)
        {
            if(a[j])
            {
                if(j>=n)
                    d[cur]|=(d[cur^1]<<(j-n));
                else d[cur]|=(d[cur^1]>>(n-j));
            }
        }
        if(d[cur][n]) return 0*printf("%d\n",i);
    }
    puts("-1");
    return 0;
}




posted @ 2017-09-01 19:45  tarjan's  阅读(10)  评论(0编辑  收藏  举报