Boxes
题意:
有n个盒子,每个盒子里要么是黑球,要么是白球,你可以花C的代码得知剩下所有盒子中黑球数量和白球数量,(只是知道总数量,并不知道具体哪个盒子里是什么),你可以可以花费wi的代价开第i个箱子。问想知道所有盒子里球的情况,花费的最少期望是多少?
题解:
首先这个C最多只用花一次,且第一次花,因为你第一次花完之后,就知道黑白所有的数量,如果你开了箱子,剩下的箱子反推就知道,所以这个C只用花一次。
如果只花一次C,那我们就要考虑剩下的箱子打开情况,按照wi升序排列,我们肯定优先打开花费小的箱子,一直开,直到开到一个后缀全是同色的位置。这样的代价:C+∑wi(1−1/(2n−i))C+\sum wi(1-1/(2^{n-i}))C+∑wi(1−1/(2n−i))
公式得到过程:
如果我们当前打算开第i个,那么就还有n-i个没开,如果不继续开箱子,说明后面都是同色的,后面同色的概率是1/2n−i1/2^{n-i}1/2n−i,如果第i个箱子开,就说明后面不都是同色的,概率就是1−1/2n−i1-1/2^{n-i}1−1/2n−i,期望就再乘上wi
当然,可以不整那么多虚的,有可能直接打开所有盒子的总花费更优,此时打开所有盒子的概率都是1,总期望就是∑i=1nwi\sum_{i=1}^nwi∑i=1nwi
两个情况取最小
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
//Fe~Jozky
const ll INF_ll=1e18;
const int INF_int=0x3f3f3f3f;
inline ll read(){ll s=0,w=1ll;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1ll;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10ll+((ch-'0')*1ll),ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
void rd_txt(){#ifdef ONLINE_JUDGE#elsefreopen("in.txt","r",stdin);#endif
}
const int maxn=1e5+9;
long double a[maxn];
long double sum[maxn];
long double poww(long double a,ll b){long double ans=1;while(b){if(b&1)ans*=a;a*=a;b>>=1; }return ans;
}
int main()
{//rd_txt();int n;double c;cin>>n>>c;for(int i=1;i<=n;i++)cin>>a[i];sort(a+1,a+1+n);for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];long double ans=c;long double t=1.0;for(int i=1;i<=n;i++){ans+=a[i]*(1.0-1.0/poww(2,n-i));}ans=min(ans,sum[n]);printf("%.8Lf\n",ans);return 0;
}