Solving ideas:
Let's set f[i][j] to represent the number of programs i n the previous i-course where a total of J people were not crushed. The answer is f[m][n_1_k]
Assume the transfer from f[i_1][w] to f[i][j](j < w)
The number of people who were not crushed should have increased by Ri_1, but some may not have been crushed before.
There are t1=j_w individuals who are new. To select from n_1_w individuals, the number of options is Ct1n_1_w
There are also t2=Ri_1_t 1 people who were never crushed. To select from w individuals, the number of options is Ct2w
For example, w=100,Ri_1=5,j=102, then t1=2,t2=3
Consider the scoring scheme for Lesson i I. If God B gets an x-score, there will be Ri_1 people with a score greater than him and n_Ri with a personal score less than or equal to him, so the total number of scenarios is
g(i)=∑x=1Ui(Ui−x)r−1xn−r
Because Ui is so large that it cannot be calculated directly, but notice that it is a polynomial whose number of times about Ui is less than or equal to n, you can use Lagrange interpolation to interpolate U=1,2...N+1 takes n+1 points and calculates the value of g(i).
Because Ri is different, it is required for each course.
Here we get the total dp equation:
f[i][j]=g(i)∑w=0jCt1n−1−wCt2wf[i−1][w]
Time complexity is O(n3)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=105,p=1e9+7;
int n,m,k;
int U[N],R[N],c[N][N],f[N][N];
int g[N],inv[N];
int ksm(int x,int y)
{
x%=p;int res=1;
for(;y;y>>=1,x=1ll*x*x%p)
if(y&1)res=1ll*res*x%p;
return res;
}
int Inter(int u,int r)
{
memset(g,0,sizeof(g));
for(int x=1;x<=n+1;x++)
{
for(int i=1;i<=x;i++)
g[x]=(g[x]+1ll*ksm(x-i,r-1)*ksm(i,n-r)%p)%p;
if(u==x)return g[x];
}
for(int i=1;i<=n+1;i++)
{
inv[i]=1;
for(int j=1;j<=n+1;j++)
if(i!=j)inv[i]=(1ll*inv[i]*(i-j)%p+p)%p;
inv[i]=ksm(inv[i],p-2);
}
int res=0;
for(int i=1;i<=n+1;i++)
{
int tmp=1ll*inv[i]*g[i]%p;
for(int j=1;j<=n+1;j++)
if(i!=j)tmp=1ll*tmp*(u-j)%p;
res=(res+tmp)%p;
}
return res;
}
int C(int i,int j)
{
if(i<0||j<0||j>i)return 0;
return c[i][j];
}
int main()
{
//freopen("lx.in","r",stdin);
//freopen("lx.out","w",stdout);
n=getint(),m=getint(),k=getint();
for(int i=1;i<=m;i++)U[i]=getint();
for(int i=1;i<=m;i++)R[i]=getint();
c[0][0]=1;
for(int i=1;i<=n;i++)
{
c[i][0]=1;
for(int j=1;j<=n;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
}
f[0][0]=1;
for(int i=1;i<=m;i++)
{
int tmp=Inter(U[i],R[i]);
for(int j=0;j<=n;j++)
{
for(int w=0;w<=j;w++)
f[i][j]=(f[i][j]+1ll*f[i-1][w]*C(n-1-w,j-w)%p*C(w,R[i]-1-(j-w))%p*tmp%p)%p;
}
}
cout<<f[m][n-1-k]<<'\n';
return 0;
}