好神的一道题,orz ljss……
因为每次要把用过的牌堆扔掉,所以其实相当于固定你的选择牌堆顺序,然后对面选择牌的堆顺序是在1~n的全排列里随机一个
首先求出p[i],代表小于等于你的第i个数的他的数的数量
先考虑一下n<=2000,k<=1e9的做法
我们的目标就是求出赢x场的情况有多少种,然后除以n!就得到了赢x场的几率,然后就可以算期望了
我们用f[i][j]表示考虑你的前i个数,从中选出j个数,并且对面任意选出j个数,你的选出的每个数与他选出的数中的一个数一一对应,并且你的每个数都大于等于其对应的那个数的方案数
转移的时候考虑i在不在选出的那j个数里,得到dp式f[i][j]=f[i-1][j]+f[i-1][j-1]*(p[i]-(j-1))
p[i]-(j-1)代表的是当前对手能选出的小于等于你的第i个数的数的数量,因为之前你有j-1个数都大于等于他的j-1个数了,而题目保证了两个序列是递增的,所以可以直接减j-1
第一维可以滚动掉,这样的话我们就可以O(n^2)求出f[n][i],以下都用f[i]来表示f[n][i]
用g[i]表示赢x场的方法数,则
接下来考虑n<=1e6,k=1或2的做法
先考虑k=1,一共有n!种排列,我们要求的是,也就是
P枚举1~n的全排列,win(P)表示在全排列P下你赢的次数,w(i)表示在P下第i场赢没赢
考虑你的第i个数对分子的贡献,他会贡献p[i]*((n-1)!)
意义是他一定要与一个小于等于他的配对,而剩下的n-1个可以任意配对
所以答案就是(sigma p[i])/n
再考虑k=2,我们要求的是,也就是
因为w(i)为0或1,所以w(i)^2那项其实相当于w(i),与k得1的情况是一样的,那么考虑后边,w(i)w(j)为1当且仅当w(i)为1且w(j)为1
当i固定时,考虑这时后边的值,可以视为i的贡献,w(j)为1的方法数为sigma k=1 to i-1 p[k],而在w(j)为1的情况下w(i)为1的方法数为p[i]-1
所以k=2也解决了
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define MAXN 1000010
#define MAXM 1010
#define ll long long
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
char xB[1<<15],*xS=xB,*xT=xB;
#define getc() (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
inline int read(){
char ch=getc();
int f=1,x=0;
while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getc();}
return x*f;
}
int n,k;
int a[MAXN],b[MAXN];
ll f[MAXN],g[MAXN];
ll p[MAXN];
ll nn,nn1;
ll fac[MAXN],ine[MAXN];
ll mi(ll x,ll y){
ll re=1;
while(y){
if(y&1){
(re*=x)%=MOD;
}
(x*=x)%=MOD;
y>>=1;
}
return re;
}
ll C(int n,int m){
return fac[n]*ine[m]%MOD*ine[n-m]%MOD;
}
int main(){
int i,j;
scanf("%d%d",&n,&k);
nn=mi(n,MOD-2);
nn1=mi(n-1,MOD-2);
for(i=1;i<=n;i++){
a[i]=read();
}
for(i=1;i<=n;i++){
b[i]=read();
}
for(i=1,j=1;i<=n;i++){
while(b[j]<=a[i]&&j<=n){
j++;
}
p[i]=j-1;
}
if(k==1){
for(i=1;i<=n;i++){
g[i]=(g[i-1]+p[i])%MOD;
}
printf("%lld\n",g[n]*nn%MOD);
}else if(k==2){
for(i=1;i<=n;i++){
g[i]=(g[i-1]+p[i])%MOD;
f[i]=(f[i-1]+2*g[i-1]%MOD*(p[i]-1))%MOD;
}
printf("%lld\n",(f[n]*nn1%MOD+g[n])*nn%MOD);
}else{
fac[0]=ine[0]=ine[1]=1;
for(i=1;i<=n;i++){
fac[i]=(fac[i-1]*i)%MOD;
}
for(i=2;i<=n;i++){
ine[i]=(MOD-MOD/i)*ine[MOD%i]%MOD;
}
for(i=1;i<=n;i++){
ine[i]=(ine[i-1]*ine[i])%MOD;
}
f[0]=1;
for(i=1;i<=n;i++){
for(j=i;j;j--){
f[j]=(f[j]+f[j-1]*(p[i]-(j-1)+MOD))%MOD;
}
}
ll ans=0;
for(i=n;i;i--){
g[i]=f[i]*fac[n-i]%MOD;
for(j=i+1;j<=n;j++){
(g[i]+=MOD-g[j]*C(j,i)%MOD)%=MOD;
}
(ans+=g[i]*mi(i,k))%=MOD;
}
printf("%lld\n",ans*ine[n]%MOD);
}
return 0;
}
/*
\
*/