您的位置:首页 > 产品设计 > UI/UE

UESTC 84 DP

2017-02-20 20:43 381 查看

题意

给n个数,可以从这n个数中连续取任意个数进行与、或、异或运算。求与、或、异或运算的期望。

题解

设dp[i]为最后一个数字为i,满足条件的数列个数。运算按位进行,求出运算后使该位等于1的数列个数,然后乘以权值,再除以(n+1)*n/2,即可得到期望。对于每种运算,状态转移分两种情况。

该位为1:

与运算:dpa[i]=dpa[i-1]+a (a代表该数字前连续为1的数字个数)

或运算:dpo[i]=dpo[i-1]+i(i代表该数字前数字个数)

异或运算:dpx[i]=dpx[i-1]+i-v(v代表该数字前数字进行异或运算,结果为1的情况个数)

该位为0:

与运算:dpa[i]=dpa[i-1]

或运算:dpo[i]=dpo[i-1]+b(i代表该数字前数字进行或运算,结果为1的情况个数)

异或运算:dpx[i]=dpx[i-1]+v(v代表该数字前数字进行异或运算,结果为1的情况个数)

注意事项

dp[i]可能会很大,因此要用long long

代码

#include <iostream>
#include<cstdio>
#include<algorithm>
#define MAXN 50010
typedef long long ll;
int num[MAXN];
ll dpa[MAXN],dpo[MAXN],dpx[MAXN];
int n;

using namespace std;

void  dp(){
dpa[0]=0,dpo[0]=0,dpx[0]=0;
int a=0,b=0,v=0;
for(int i=1;i<=n;i++){
if(1&num[i]){
a++;
dpa[i]=dpa[i-1]+a;
dpo[i]=dpo[i-1]+i;
dpx[i]=dpx[i-1]+i-v;
b=i;
v=i-v;
}else{
a=0;
dpa[i]=dpa[i-1];
dpo[i]=dpo[i-1]+b;
dpx[i]=dpx[i-1]+v;
}
num[i]=num[i]>>1;
}
}

int main()
{
int t;
scanf("%d",&t);
for(int ks=1;ks<=t;ks++){
scanf("%d",&n);
int maxnum=0;
for(int i=1;i<=n;i++){
scanf("%d",&num[i]);
maxnum=max(maxnum,num[i]);
}
int j=1;
double ans1=0,ans2=0,ans3=0;
while(maxnum>0){
dp();
ans1+=dpa
*j;
ans2+=dpo
*j;
ans3+=dpx
*j;
j=j<<1;
maxnum=maxnum>>1;
}
double x=(double)n*(n+1)/2;
printf("Case #%d: ",ks);
printf("%.6f %.6f %.6f\n",ans1/x,ans2/x,ans3/x);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: