题目描述
有标有数字为1~
n≤1000,ai≤108,m≤108
题解
nm−=n×(n−1)×(n−2)×⋯×(n−m+1)=A(n,m)即排列数
我们先枚举哪些位置有乘号
现在我们考虑把1,2,3,4四个数字填到__×__这样子的算式中。假设m=2。把式子展开
ab¯¯¯×cd¯¯¯=(a×10+b)×(c×10+d)=a×c×10×10+a×d×10×1+b×c×1×10+b×d×1×1=100ac+10ad+10bc+bd
我们还有另外23个式子呢
ab¯¯¯×dc¯¯¯ba¯¯¯×cd¯¯¯ba¯¯¯×dc¯¯¯⋮
另外我们发现,ac和ad对答案的贡献都是相似的(因为除了乘积不同之外没有什么区别)我们考虑计算系数和出现次数
系数会有10×10,10×1,1×10,1×1,那么怎样计算出现次数呢?
先钦定这两个数字放的位置(就是系数),剩下那些空位总共有两个,还剩下两个数没填,方案数就是22−=2
最后还要乘上选择乘号的方案数21−=2
于是总的贡献就是
(1×2+1×3+1×4+⋯+4×3)×(100+10+10+1)×2×2=???
现在我们来考虑更复杂的情况
sum为所有数字卡片的个数和,gi,j为前i个数字中选出
这里只讲一下f的推导
那么10ac+bc的系数就是ab¯¯¯×c的系数(前一个位置的系数),10a+b的系数就是到上一个乘号前一个位置的系数。所以我们可以枚举上一个乘号是哪个位置,然后转移
gi,j=∑k=0aigi−1,k−j×ik×(jk)×ak−ifi,j=fi−1,j×10+∑k=1ifk,j−1si=g9,i+1×fn,i×(sum−i−1)n−i−(i+1)−−−−−−−×mi−
排列组合什么的可以预处理或暴力算
时间复杂度:O(n2)
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
ll p=1000000007;
int a[10];
ll g[10][1010];
ll f[1010][1010];
ll s[1010][1010];
ll aa[10][1010];
ll pa[10][1010];
ll cc[1010][1010];
ll am[1010];
ll geta(ll n,ll m)
{
ll s=1;
int i;
for(i=1;i<=m;i++)
s=s*(n-i+1)%p;
return s;
}
int main()
{
// freopen("c.in","r",stdin);
// freopen("c.out","w",stdout);
int n,m,sum=0;
scanf("%d%d",&n,&m);
int i;
for(i=1;i<=9;i++)
{
scanf("%d",&a[i]);
sum+=a[i];
}
int j,k;
for(i=1;i<=9;i++)
{
pa[i][0]=1;
aa[i][0]=1;
for(j=1;j<=n;j++)
{
pa[i][j]=pa[i][j-1]*i%p;
aa[i][j]=aa[i][j-1]*(a[i]-j+1)%p;
}
}
for(i=0;i<=n;i++)
{
cc[i][0]=1;
for(j=1;j<=i;j++)
cc[i][j]=(cc[i-1][j]+cc[i-1][j-1])%p;
}
g[0][0]=1;
for(i=1;i<=9;i++)
for(j=0;j<=n;j++)
for(k=0;k<=j&&k<=a[i];k++)
g[i][j]=(g[i][j]+g[i-1][j-k]*pa[i][k]%p*cc[j][k]%p*aa[i][k]%p)%p;
for(i=1;i<=n;i++)
{
f[i][0]=(f[i-1][0]*10+1)%p;
s[i][0]=(s[i-1][0]+f[i][0])%p;
for(j=1;j<=n;j++)
{
f[i][j]=f[i-1][j]*10%p;
if(i>2)
f[i][j]=(f[i][j]+s[i-2][j-1])%p;
s[i][j]=(f[i][j]+s[i-1][j])%p;
}
}
am[0]=1;
for(i=1;i<=n;i++)
am[i]=am[i-1]*(m-i+1)%p;
ll ans=0;
for(i=0;i<=(n-1)/2&&i<=m;i++)
ans=(ans+g[9][i+1]*f[n][i]%p*geta(sum-i-1,n-2*i-1)%p*am[i]%p)%p;
printf("%lld\n",ans);
return 0;
}