Description
度度熊在玩一个叫做“打怪兽”的游戏。
游戏的规则是这样的。
度度熊一开始会有一个初始的能量值。每次遇到一个怪兽,若度度熊的能量值≥ 怪兽的能量值并且度度熊剩余血量≥怪兽的攻击力,那么怪兽将会被打败,度度熊的能量值增加1,度度熊的血量减少该怪兽的攻击力,否则度度熊死亡(度度熊的血量刚好减到0时并不会死亡,还能继续战斗),游戏结束。
若怪兽全部打完,游戏也将会结束。
共有n个怪兽,由于度度熊比较弱,它一开始只有1点能量值。
n个怪兽排列随机,也就是说共有n!种可能,度度熊想知道结束时它能量值的期望。
注意这里怪兽的编号是从1开始到编号n为止且编号为i的怪兽能量值为i-1。
由于小数点比较麻烦,所以你只需要输出期望*n!关于1000000007取模后的值就可以了!
在样例中有5个怪兽,它们的能量分别为0,1,2,3,4,其中每个怪兽的攻击力都为1。
Input
多组数据。对于每一组数据:
第一行两个数n,m表示有n只怪兽,度度熊的初始血量(1<=n<=500000,1<=m<=10^9)。
接下来一行n个数ai表示编号为i的怪兽的攻击力(0<=ai<=m)。
Output
一行表示答案。
Sample Input
5 4
1 1 1 1 1
Sample Output
104
Solution
令
num[i]
为至少干掉
i
只怪兽的方案数,则干掉
进而 ans=∑i=1n−1i⋅(num[i]−num[i+1])+num[n]=∑i=1nnum[i]
考虑求
num[i]
,给怪兽编号为
0
~
1
.若
2
.若
3
.若
现在问题变成如何快速得到
sum
,即满足
m−∑j=0iaj+ak≥0
的
bk
之和,注意到随着
i
的增大,
注意上面只求了
num[1]
~
num[n−1]
,对于
num[n]
,如果
m−∑i=0n−1ai≥0
,说明这
n
只怪兽可以随便干掉,由第
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
namespace fastIO
{
#define BUF_SIZE 100000
//fread -> read
bool IOerror=0;
inline char nc()
{
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if(p1==pend)
{
p1=buf;
pend=buf+fread(buf,1,BUF_SIZE,stdin);
if(pend==p1)
{
IOerror=1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch)
{
return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
}
inline void read(int &x)
{
char ch;
while(blank(ch=nc()));
if(IOerror)return;
for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0');
}
inline void readlld(ll &x)
{
char ch;
while(blank(ch=nc()));
if(IOerror)return;
for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10ll+ch-'0');
}
#undef BUF_SIZE
};
using namespace fastIO;
#define mod 1000000007
#define maxn 500005
int n,a[maxn],f[maxn],p2[maxn];
ll m;
struct node
{
int v;
bool operator<(const node&b)const
{
return a[v]>a[b.v];
}
};
priority_queue<node>que;
int main()
{
f[0]=1;
for(int i=1;i<=500000;i++)f[i]=(ll)i*f[i-1]%mod;
p2[0]=1;
for(int i=1;i<=500000;i++)p2[i]=(p2[i-1]<<1)%mod;
while(1)
{
read(n),readlld(m);
if(IOerror)break;
for(int i=0;i<n;i++)read(a[i]);//scanf("%d",&a[i]);
int sum=0,ans=0;
m-=a[0];
for(int i=1;i<n;i++)
{
if(m<0)
{
m-=a[i];
while(!que.empty())
{
int j=que.top().v;
if(m+a[j]>=0)break;
que.pop();
sum-=p2[max(0,j-1)];
if(sum<=0)sum+=mod;
}
ans+=(ll)sum*f[n-i]%mod;
if(ans>=mod)ans-=mod;
}
else
{
m-=a[i];
if(m<0)
{
while(!que.empty())que.pop();
for(int j=0;j<=i;j++)
if(m+a[j]>=0)
{
que.push((node){j});
sum+=p2[max(0,j-1)];
if(sum>=mod)sum-=mod;
}
ans+=(ll)sum*f[n-i]%mod;
if(ans>=mod)ans-=mod;
}
else
{
ans+=(ll)p2[i]*f[n-i]%mod;
if(ans>=mod)ans-=mod;
}
}
}
if(m>=0)
{
ans+=p2[n-1];
if(ans>=mod)ans-=mod;
}
printf("%d\n",ans);
}
return 0;
}