题目描述

  有标有数字为\(1\)~\(9\)的卡片各\(a_1,a_2\cdots a_9\)张,还有标有乘号的卡片\(m\)张。从中取出\(n\)张按任意顺序排列,取出两个乘号相邻和乘法在边界上的非法式子,剩下的都是合法式子。求所有合法式子的方案的值的和。两张数字相同的卡片是不同的,两张乘号也是不同的。答案模\({10}^9+7\)

  \(n\leq 1000,a_i\leq {10}^8,m\leq{10}^8\)

题解

  \(n^\underline{m}=n\times(n-1)\times(n-2)\times\cdots\times(n-m+1)=A(n,m)\)即排列数

  我们先枚举哪些位置有乘号

  现在我们考虑把\(1,2,3,4\)四个数字填到\(\_\_\times\_\_\)这样子的算式中。假设\(m=2\)。把式子展开

\[\begin{align}
&~~~~~\overline{ab}\times\overline{cd}\\
&=(a\times10+b)\times(c\times10+d)\\
&=a\times c\times 10\times 10+a\times d\times 10\times 1+b\times c\times 1\times 10+b\times d\times 1\times 1\\
&=100ac+10ad+10bc+bd
\end{align}
\]

  我们还有另外\(23\)个式子呢

\[\overline{ab}\times\overline{dc}\\
\overline{ba}\times\overline{cd}\\
\overline{ba}\times\overline{dc}\\
\vdots
\]

  另外我们发现,\(ac\)和\(ad\)对答案的贡献都是相似的(因为除了乘积不同之外没有什么区别)我们考虑计算系数和出现次数

  系数会有\(10\times 10,10\times 1,1\times 10,1\times 1\),那么怎样计算出现次数呢?

  先钦定这两个数字放的位置(就是系数),剩下那些空位总共有两个,还剩下两个数没填,方案数就是\(2^\underline{2}=2\)

  最后还要乘上选择乘号的方案数\(2^\underline{1}=2\)

  于是总的贡献就是

\[(1\times 2+1\times 3+1\times 4+\cdots+4\times 3)\times(100+10+10+1)\times 2\times 2=???
\]

  现在我们来考虑更复杂的情况

  \(sum\)为所有数字卡片的个数和,\(g_{i,j}\)为前\(i\)个数字中选出\(j\)个代表数字的乘积的和,\(f_{i,j}\)为前\(i\)个空填了\(j\)个乘号的合法算式的系数和,\(s_i\)为这\(n\)个空中填入\(i\)个乘号的答案。

  这里只讲一下\(f\)的推导

\[\begin{align}
&~~~~~\overline{ab}\times \overline{cd}\\
&=100ac+10ad+10bc+bd\\
&=10(10ac+bc)+(10a+b)d\\
\end{align}
\]

  那么\(10ac+bc\)的系数就是\(\overline{ab}\times c\)的系数(前一个位置的系数),\(10a+b\)的系数就是到上一个乘号前一个位置的系数。所以我们可以枚举上一个乘号是哪个位置,然后转移

\[g_{i,j}=\sum_{k=0}^{a_i}g_{i-1,k-j}\times i^k\times \binom{j}{k}\times a_i^\underline{k}\\
f_{i,j}=f_{i-1,j}\times10+\sum_{k=1}^{i}f_{k,j-1}\\
s_i=g_{9,i+1}\times f_{n,i}\times {(sum-i-1)}^\underline{n-i-(i+1)}\times m^\underline{i}
\]

  排列组合什么的可以预处理或暴力算

  时间复杂度:\(O(n^2)\)

代码

#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;
}

【XSY1591】卡片游戏 DP的更多相关文章

  1. 【sicily】卡片游戏

    卡片游戏  Time Limit: 1sec    Memory Limit:32MB Description 桌上有一叠牌,从第一张牌(即位于顶面的牌)开始从上往下依次编号为1~n.当至少还剩两张牌 ...

  2. Sicily 1931. 卡片游戏

    题目地址:1931. 卡片游戏 思路: 纯属数据结构中队列的应用,可以练练手. 具体代码如下: #include <iostream> #include <queue> usi ...

  3. 卡片游戏(hdu4550)贪心

    卡片游戏 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submi ...

  4. nyoj905 卡片游戏

    卡片游戏 时间限制:1000 ms  |  内存限制:65535 KB 难度:1   描述 小明最近宅在家里无聊,于是他发明了一种有趣的游戏,游戏道具是N张叠在一起的卡片,每张卡片上都有一个数字,数字 ...

  5. 1233: 传球游戏 [DP]

    1233: 传球游戏 [DP] 时间限制: 1 Sec 内存限制: 128 MB 提交: 4 解决: 3 统计 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做 ...

  6. NYOJ 905 卡片游戏

    卡片游戏 时间限制:1000 ms  |  内存限制:65535 KB 难度:1 描写叙述 小明近期宅在家里无聊.于是他发明了一种有趣的游戏.游戏道具是N张叠在一起的卡片,每张卡片上都有一个数字,数字 ...

  7. 游戏 DP

    游戏 DP [题意描述] 小喵喵喜欢玩 RPG 游戏.在这款游戏中,玩家有两个属性,攻击和防御,现在小喵喵的攻击和防御都是 1,接下来小喵喵会依次遇到 n 个事件.事件有两种. 1.小喵喵经过修炼,角 ...

  8. Java实现 LeetCode 822 翻转卡片游戏(暴力)

    822. 翻转卡片游戏 在桌子上有 N 张卡片,每张卡片的正面和背面都写着一个正数(正面与背面上的数有可能不一样). 我们可以先翻转任意张卡片,然后选择其中一张卡片. 如果选中的那张卡片背面的数字 X ...

  9. [LuoguP1005]矩阵取数游戏 (DP+高精度)

    题面 传送门:https://www.luogu.org/problemnew/show/P1005 Solution 我们可以先考虑贪心 我们每一次都选左右两边尽可能小的数,方便大的放在后面 听起来 ...

随机推荐

  1. hibernate异常找不到get方法org.hibernate.PropertyNotFoundException: Could not find a getter for did in class com.javakc.hibernate.manytomany.entity.CourseEntity

    属性的get方法没找到,可能是CourseEntity类中对应属性没有get方法,如果有就看CourseEntity.hbm.xml属性名称,应该是写错了不和CourseEntity类中属性名相同,修 ...

  2. Vue父子传值

    昨天创建完项目以后,今日首先使用项目来做一个简单的导航栏体会一下Vue的使用 1.项目的结构: 2.首先在Vheader.Vue中编辑代码: <template> <header c ...

  3. echarts使用笔记四:双Y轴

    1.双Y轴显示数量和占比 app.title = '坐标轴刻度与标签对齐'; option = { title : { //标题 x : 'center', y : 5, text : '数量和占比图 ...

  4. ShowDoc上手

    ShowDoc是什么 每当接手一个他人开发好的模块或者项目,看着那些没有写注释的代码,我们都无比抓狂.文档呢?!文档呢?!Show me the doc !! 程序员都很希望别人能写技术文档,而自己却 ...

  5. C#设计模式之5:简单工厂和工厂方法模式

    工厂模式包含三种,简单工厂模式,工厂方法模式,抽象工厂模式.这三种都是解决了一个问题,那就是对象的创建问题.他们的职责就是将对象的创建和对象的使用分离开来. 当我们创建对象的时候,总是会new一个对象 ...

  6. linux安装ssh服务

    1.安装openssh-server sudo apt-get install openssh-server 2.检查openssh-server是否安装成功 sudo ps -e | grep ss ...

  7. 在阿里云上部署 Postfix

    Postfix 可以很方便的在一台机器上部署 smtp 服务,在 centos 上来说的话可以使用: sudo yum install postfix sudo systemctl enable po ...

  8. 关于mysql远程登录问题

    问题:mysql不能实现远程登录 前提:mysql开启了远程登录账号,安全组也放行了3306,防火墙是iptables,也加入了3306放行,但是还是不能实现远程访问 解决办法,使用iptables ...

  9. 集合之TreeMap(含JDK1.8源码分析)

    一.前言 前面所说的hashMap和linkedHashMap都不具备统计的功能,或者说它们的统计性能的时间复杂度都不是很好,要想对两者进行统计,需要遍历所有的entry,时间复杂度比较高,此时,我们 ...

  10. 初识Anrdiod SDK

    概念 SDK:(software development kit)软件开发工具包.被软件开发工程师用于为特定的软件包.软件框架.硬件平台.操作系统等建立应用软件的开发工具的集合. 因此,Android ...