题目大意
听着自己美妙的曲子,小Z进入了梦乡。在梦中,小Z仿佛又回到了自己纵横考场的年代。在梦中,小Z参加了一场考试,这场考试一共有n道题,每道题的最终得分都是一个大于等于0的整数。然而醒来后,小Z忘记了自己每道题的得分。他只记得自己计算过m次一些题目的分数和,每道题都被计算过,并且只被计算过一次。除此之外他还记得其中t道题的满分分别是多少(一道题的得分不会超过满分)。现在小Z想知道他这场考试有多少种得分情况(至少有一道题的得分不同就算不同的情况),因为这个答案可能很大,你只需要输出答案对1,000,000,007取模后的结果即可。
解题思路
考虑没有限制的情况,可以用隔板原理求出。考虑到限制很少可以用容斥原理,强制分配使其非法,用隔板原理求出,对于没限制的情况可以提前求出。
code
using namespace std;
int const mxn=1e6,mo=1e9+7;
int n,m,t,ans,cnt,preans=1,tag[mxn+10],a[mxn+10][2],b[30][2],d[30][2],renum[mxn+10],bel[mxn+10],fact[mxn*2+10],ni[mxn*2+10];
int c(int x,int y){
return 1ll*fact[x]*ni[y]%mo*ni[x-y]%mo;
}
void dfs(int now,int tag){
if(now>t){
int tmp=1;
fo(i,1,cnt)
tmp=1ll*tmp*((d[i][1]>=0)?(c(d[i][1]+d[i][0]-1,d[i][0]-1)):0)%mo;
ans=(ans+1ll*tag*preans*tmp%mo)%mo;
return;
}
d[bel[b[now][0]]][1]-=b[now][1]+1;
dfs(now+1,-tag);
d[bel[b[now][0]]][1]+=b[now][1]+1;
dfs(now+1,tag);
}
int Pow(int x,int y){
int z=1;
while(y){
if(y&1)z=1ll*z*x%mo;
x=1ll*x*x%mo;
y=y>>1;
}
return z;
}
int read(){
int v=0;char ch=getchar();
for(;(ch<'0')||(ch>'9');ch=getchar());
for(;(ch>='0')&&(ch<='9');v=v*10+ch-'0',ch=getchar());
return v;
}
int main(){
//freopen("equation.in","r",stdin);
//freopen("equation.out","w",stdout);
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
n=read();m=read();int x;
fact[0]=ni[0]=1;fo(i,1,mxn*2)fact[i]=1ll*fact[i-1]*i%mo,ni[i]=Pow(fact[i],mo-2);
fo(i,1,m){
a[i][0]=read();
fo(j,1,a[i][0])x=read(),bel[x]=i;
a[i][1]=read();
}
t=read();
fo(i,1,t)b[i][0]=read(),b[i][1]=read(),tag[bel[b[i][0]]]=1;
fo(i,1,m)if(tag[i])cnt++,d[cnt][0]=a[i][0],d[cnt][1]=a[i][1],renum[i]=cnt;
else preans=1ll*preans*c(a[i][0]+a[i][1]-1,a[i][0]-1)%mo;
fo(i,1,t)bel[b[i][0]]=renum[bel[b[i][0]]];
dfs(1,1);
printf("%d",(ans%mo+mo)%mo);
return 0;
}