UOJ Logo AnzheWang的博客

博客

CF 788C另类做法

2018-01-10 19:38:12 By AnzheWang

原题地址:http://codeforces.com/contest/788/problem/C

题意大致是这样的:

你有k个种类的可口可乐,每瓶的二氧化碳浓度为$a_i/1000$(每瓶有无限个,$a_i$是正整数,可以相同)

你需要调配出浓度为$n/1000$(n也是正整数)的可口可乐

二氧化碳浓度为二氧化碳体积除以可口可乐总体积

$1≤k≤1e6,0≤n≤1000,0≤a_i≤1000$

很明显一开始都会这么想:

首先套路地将$a_i$减去$n$,接着我们就是要让选出来的可乐浓度和为0

因为每种浓度有无限瓶,那么就可以去重了,k就缩到了1000。

所以接下来我们就可以考虑背包:

我们将$a_i$分成大于0和小于0的(有等于0的就做完了)

分别dp在f数组和g数组里。

就是这样:

memset(f, 63, sizeof f);
memset(g, 63, sizeof g);
f[0] = g[0] = 0;
for(int i = 1; i <= k; i++) {
    if(a[i] < 0) {
        for(int j = -a[i]; j <= 1000000; j++)
            f[j] = std::min(f[j], f[j+a[i]]+1);
    } 
    if(a[i] > 0) {
        for(int j = a[i]; j <= 1000000; j++)
            g[j] = std::min(g[j], g[j-a[i]]+1);
    }
}

接着对所有的f[x]+g[x]中找最小的就好了。

复杂度O(k*1000*1000),k即使是1000也是过不了的。

然后正解大致是枚举答案,bitset来优化dp。

但是我的思路却奇怪了:

我想,如果可乐的浓度种类数很多,那么在答案取到最小值的时候,背包的容量也不会很大,因为浓度可以说非常的挤,于是我打算让上界不固定。

memset(f, 63, sizeof f);
memset(g, 63, sizeof g);
f[0] = g[0] = 0;
for(int i = 1; i <= k; i++) {
    if(a[i] < 0) {
        for(int j = -a[i]; j <= 1000000/k; j++)
            f[j] = std::min(f[j], f[j+a[i]]+1);
    } 
    if(a[i] > 0) {
        for(int j = a[i]; j <= 1000000/k; j++)
            g[j] = std::min(g[j], g[j-a[i]]+1);
    }
}

复杂度O(1000000)

接着交上去就过了。

看了一下过的人发现好像只有我一个人是这种做法

但是我不能证明这个做法的正确性,或者,如果是错的,各位能不能卡掉。

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。