原题:
问题描述
“有啊”是百度旗下的电子商务购物平台,每天都有上百万的用户在平台上搜索自己想要购买的商品。为了给用户更 好的搜索体验,工程师们准备做一次搜索策略的调研工作。
假设对于某一个特定的查询词来说,一共有N个相关商品,并且通过人工标注得到每个商品与查询词的相关度reli。 当用户输入这个查询词时,可以采取一种非常简单的响应策略,就是在N个相关商品中随机的找一段连续的商品子序列返回给用户。 工程师认为,在每次返回结果中相关度的最小值代表了本次搜索结果的分数score。
用户在搜索时,心中往往会对结果有个期望分数expect,当搜索结果的分数score高于用户的预期 expect时,该用户的满意度为score – expect;否则用户的满意度为0。
假设在上述响应策略中,返回的子序列是完全随机的(即每段连续子序列被选中的概率完全相同),你的任务是计算 每个用户满意度的数学期望。
输入格式
输入第一行包含一个正整数T,表示测试数据的组数。每组测试数据的第一行为相关商品的数量N, 第二行为N个整数,分别表示每个商品与查询词的相关度reli(用空格分隔)。 第三行为一个正整数M,表示参与调研的用户数量,接下来的M行中的每一行都是一个整数expect,表示该用户在搜索时预期的分数值。 其中1 <= T <= 10,1 <= N, M <= 100,000, -109 <= reli, expect <= 109。
输出格式
对于每组测试数据,首先输出一行 “Case #:”,其中#表示测试数据编号(从1开始),注意空格与大小写。 接下来的M行,按照输入顺序依次给出每个用户在这种响应策略下满意度的期望值,每个用户占一行。 为了避免精度问题,期望值用最简分数 “A/B” 表示,其中A与B互质,B是正整数。当结果是整数时,应只输出A。
样例输入
3
3
13 5
1
2
4
5-2 1 4
2
1
-1
3
24 10
1
0
样例输出
Case1:
5/6
Case2:
7/10
3/2
Case3:
4
样例说明
在Case 1中,可能返回的子序列一共有6个[1], [3], [5], [1 3], [3 5], [1 3 5],对应的分数(相关度最小值)为1, 3, 5, 1, 3, 1,用户满意度依次为0, 1, 3, 0, 1, 0。每个子序列被返回的概率相同,即为1/6。根据数学期望的定义 可以得出该用户的满意度期望值是5/6。
题意分析:
题意比较明确,给一个长度为n的序列ai,然后M次询问。每次询问是给出一个数k,然后在序列A里面随机取一段连续的序列,其中这个序列中的最小值为x,然后这个序列的得分是max(x-k, 0),问得分的数学期望是多少。
关键思路:
测试数据:
4
3
1 3 5
1
2
4
5 -2 1 4
2
1
-1
3
2 4 10
1
0
3
2 2 2
1
1
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<set>
#include<stack>
#include<map>
using namespace std;
typedef long long LL;
#define CLR(a,b) memset(a,b,sizeof(a))
const int N = 100000+20;
LL gcd(LL a,LL b)
{
if(a == 0)return b;
return gcd(b%a,a);
}
map<int,LL> G;
typedef pair<int,int> PII;
int n,m;
int a[N];
LL l[N],r[N];
int bef[N];
PII o[N];
LL sufix[N],sufixsum[N];
int tot;
map<int,LL>::iterator ite;
void solve(LL x)
{
int pos = upper_bound(o + 1, o + tot + 1, (PII)make_pair(x, 0)) - o;
LL p = sufixsum[pos] - sufix[pos] * x;
LL q = n * (n+1) / 2;
LL d = gcd(p,q);
p /= d; q /= d;
if(q == 1) printf("%lld\n",p);
else printf("%lld/%lld\n",p,q);
}
void init()
{
CLR(bef,-1);
sort(o + 1, o + n + 1);
tot = 0;
for(int i = 1 ; i <= n ; i ++){
if(i > 1 && o[i].first == o[i-1].first){
bef[o[i].second] = o[i-1].second;
}else o[++tot] = o[i];
}
stack<int> st;
for(int i = 1; i <= n ; i++){
while(!st.empty() && a[st.top()] >= a[i])st.pop();
if(st.empty())l[i] = 0;
else l[i] = st.top();
st.push(i);
}
while(!st.empty())st.pop();
for(int i = n; i >= 1 ; i--){
while(!st.empty() && a[st.top()] >= a[i])st.pop();
if(st.empty())r[i] = n+1;
else r[i] = st.top();
st.push(i);
}
while(!st.empty())st.pop();
G.clear();
for(int i = 1; i <= n ; i ++){
if(bef[i] == -1){
G[a[i]] += (i - l[i]) * (r[i] - i);
}else{
if(r[bef[i]] < i){
G[a[i]] += (i - l[i]) * (r[i] - i);
}else{
G[a[i]] += (i - bef[i]) * (r[i] - i);
}
}
}
sufixsum[tot+1] = sufix[tot+1] = 0;
for(int i = tot ; i >= 1 ; i--){
int val = o[i].first;
sufix[i] = sufix[i+1] + G[val];
sufixsum[i] = sufixsum[i+1] + val * G[val];
}
}
int main()
{
int T,cas = 0;
scanf("%d",&T);
while(T--){
cas ++;
scanf("%d",&n);
for(int i = 1; i <= n ;i ++){
scanf("%d",&a[i]);
o[i] = make_pair(a[i], i);
}
init();
int m;
scanf("%d",&m);
printf("Case %d:\n",cas);
for(int i = 0; i < m ; i ++){
int x;
scanf("%d",&x);
solve(x);
}
}
return 0;
}