2018.11.07【校內模擬】異或(數位DP)(數學期望)
阿新 • • 發佈:2018-11-10
傳送門
解析:
蒟蒻考場上只想了隨機情況下的期望,於是就拿了部分分滾粗了。。。
其實最優情況下的期望我好像還推錯了,最後學習了標解才會的。
我好菜啊。。。希望今年NOIP不要打醬油就行了。
思路:
首先隨機的情況其實非常好想。我們只需要考慮每個位出現 的概率就行了,其實就是統計每個位出現 的方案數就行了,這個隨便亂搞一下都行,我是用的 的做法。
然後最優化其實只需要按照數位DP的套路來就行了,我們固定一個字首緊挨上界,然後考慮後面能夠怎麼填就行了。去看標解吧,寫得夠清楚了。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline void out(double x){
re int cnt=0;
while(x>10)++cnt,x/=10;
while(x<1.0)--cnt,x*=10;
printf("%.5f %d",x,cnt);
}
inline double calc0(ll n){
static ll cnt[65];
memset(cnt,0,sizeof cnt);
for(int re i=62;~i;--i){
if(n&(1ll<<i)){
for(int re j=i+1;j<=62;++j)if(n&(1ll<<j))cnt[j]+=1ll<<i;
for(int re j=i-1;~j;--j)cnt[j]+=1ll<<(i-1);
}
}
double res=0;
for(int re i=62;~i;--i){
if(cnt[i]){
double x=(double)cnt[i]/(1.0*n);
res+=2*x*(1-x)*(1ll<<i);
}
}
return res;
}
inline double calc1(ll n){
ll delta,hi=1,tot;
for(--n;hi<=n;hi<<=1);
delta=hi-1;hi>>=1;
double res=1.0*delta*(n+1-hi)/(1.0*n+1);
res+=1.0*hi*hi/(1.0*n+1);
tot=hi,delta>>=1;
while(hi>1){
hi>>=1;delta>>=1;
if(n&hi){
res+=1.0*tot*hi/(1.0*n+1);
res+=1.0*(tot>>=1)*delta/(1.0*n+1);
}
else res+=1.0*(tot>>1)*hi/(1.0*n+1);
}
return res;
}
ll n;
double p;
signed main(){
cin>>n>>p;
out(calc0(n)*(1-p)+calc1(n)*p);
return 0;
}