原题连接:
http://poj.org/problem?id=2393
本题题意是:有n周,每周制作+运输酸奶的价格c,需求y都有变化,另有仓库,可储存任意多的酸奶,每周每单位储存价格恒定为s,求n周最少的总成本。
本题的主要问题是:第i周的酸奶要不要之前就制作好存下来,还是直接做完卖了,就是存与不存的问题。
下面我们来探寻一下存与不存的条件。
n s
c[i], y[i] c[k],y[k]
if( (c[k]-c[i])*y[k] >= (k-i)sy[k] ) 存
else 不存
即 c[k]-c[i]~~(k-i)*s 的大小关系,大于等于存,小于不存。
不过,问题来了:
1.假设从i周开始,i+1–m-1周都在i周制作并储存,那如果在第m周同样满足可以在第i周存的条件,但会不会在i+1–m-1之间某一周k(i<k<m)也满足存的条件,且成本更低?
2.如果i在k周不满足存的条件,那在m(m>k)周会不会重新出现在i周满足存的条件呢?
为了简化问题,我们将问题 1 ,问题 2 的答案都假设为否定。
证明问题 1:
n s
c[i] y[i] c[k] y[k] c[m] y[m]
已知:c[k]-c[i]>=(k-i)*s;
设 c[k]-c[i]=d;则d>=(k-i)*s;
比较c[m]-c[i]-(m-i)·s–c[m]-c[k]-(m-k)·s的大小(注意,不是比较c[m]-c[i]–c[m]-c[k]的大小)
亦即比较 c[m]-c[i]-(m-i)·s-(c[m]-c[k]-(m-k)·s)–0的大小
化简可得 c[k]-c[i]-(k-i)*s=d-(k-i)*s~~0;
而d>=(k-i)*s,故d-(k-i)*s>=0;
因此c[m]-c[i]-(m-i)*s>=c[m]-c[k]-(m-k)*s;
从结论可知,即使在第k周可以存,也不比在第i周存来的有利,成本一定比第i周的高,于是命题得以证明,问题 1 答案为否定。
证明问题 2:
n s
c[i] y[i] c[k] y[k] c[m] y[m]
已知:c[k]-c[i]<(k-i)*s;
设 c[k]-c[i]=d;则d<(k-i)*s;
由问题 1 的过程可得
c[m]-c[i]-(m-i)*s<c[m]-c[k]-(m-k)*s;
因此,即使第m周的酸奶可以在第i周先制作存下来,也不比在第k周制作后存下来,成本一定比第k周高,于是问题 2 答案为否定。
总结:
1.i+1–m-1,m周的酸奶都可以在第i周制作后存下来,就不必考虑m周的酸奶可不可以在i+1–m-1制作后存下来了——只需考虑开头与结尾的关系,不需考虑中间
2.k周不可以在i周存,新的起点,即新的存储周直接定为k,不必考虑 i 对 k 周后面的影响了——新起点即为旧终点,旧起点对后面的影响不需考虑
伪代码如下:
输入 n,s
输入 c[n],y[n]
long long sum,flag=0;//flag为起点,初始为0
for(i=0;i<=n-1;i++){
if(满足存的条件)sum+=c[flag]·y[i]+s·(i-flag)·y[i]
else sum+=c[i]*y[i] flag=i;}
输出sum。
代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
long long c[10005],y[10005];
int main()
{
int n; //while(1){
long long s,sum=0,flag;
int i;
scanf("%d %lld",&n,&s);
flag=0;
for(i=0;i<=n-1;i++)
scanf("%lld %lld",&c[i],&y[i]);
for(i=0;i<=n-1;i++)
{
if(i==0) sum+=c[i]*y[i];
else
{
if(c[i]-c[flag]>=s*(i-flag))
{
sum+=c[flag]*y[i]+s*(i-flag)*y[i];
}
else
{
sum+=c[i]*y[i];
flag=i;
}
}
// printf("%d %lld\n",flag,sum);
}
printf("%lld\n",sum);//}
return 0;
}
本题的证明出来的结论要好好消化,下回遇到相似的就不用再证了。此外本题有一个特点——不可以排序。所以,至少按你目前的水平,千万别排序。