点此看题面

大致题意: 有一个长度为\(n\)的数列,每个位置上数字的值在\([1,m]\)范围内,则共有\(m^n\)种可能的数列。分别求出每个数列中本质不同的子序列个数,然后求和。

一些分析

首先,我们单独考虑空序列的个数\(m^n\),然后接下来就可以只考虑非空序列的个数了。

假设有一个长度为\(i\)的子序列(\(1\le i\le n\)),且其在序列中的位置分别为\(pos_1,pos_2,...,pos_i\),值分别为\(val_1,val_2,...,val_i\)。

则我们强制在\(1\sim pos_1-1\)范围内不能出现\(val_1\),\(pos_1+1\sim pos_2-1\)范围内不能出现\(val_2\),以此类推。

所以,在前\(pos_i\)个位置中,除\(pos_{1\sim i}\)这\(i\)个位置填\(val_{i\sim i}\)外,如上所述,其余\(pos_i-i\)个位置各有\(m-1\)种填法。

而在第\(pos_i\)个位置之后就可以随便填了,每个位置都有\(m\)种填法。

推式子

通过之前的分析,于是得到式子如下:

\[\sum_{i=1}^nm^i\sum_{j=i}^nC_{j-1}^{i-1}(m-1)^{j-i}m^{n-j}
\]

对于这个式子的解释:

首先,用\(i\)枚举子序列长度,而长度为\(i\)的子序列共有\(m^i\)种可能。

接下来\(j\)枚举\(pos_i\),而\(pos_{1\sim i-1}\)依次选择\([1,pos_i-1]\)(即这里的\([1,j-1]\))这个范围内的任意位置都是合法的,就相当于在\(j-1\)个位置中选择\(i-1\)个位置,方案数就是\(C_{j-1}^{i-1}\)。

从前文可得,\(pos_i-i\)(即这里的\(j-i\))个位置有\(m-1\)种填法,\(n-pos_i\)(即这里的\(n-j\))个位置有\(m\)种填法。

于是便得到上述式子。

然后就是化简:

先移项,把\(m^i\)移进去得到:

\[\sum_{i=1}^n\sum_{j=i}^nC_{j-1}^{i-1}(m-1)^{j-i}m^{n-j+i}
\]

改变枚举顺序,得到:

\[\sum_{j=1}^n\sum_{i=1}^jC_{j-1}^{i-1}(m-1)^{j-i}m^{n-j+i}
\]

观察到组合数中的\(i-1\)和\(j-1\),不难想到直接将枚举的\(i,j\)减\(1\),即:

\[\sum_{j=0}^{n-1}\sum_{i=0}^{j-1}C_j^i(m-1)^{(j+1)-(i+1)}m^{n-(j+1)+(i+1)}
\]

然后我们可以化简一下系数,发现这些\(1\)和\(-1\)恰好抵消了,得到:

\[\sum_{j=0}^{n-1}\sum_{i=0}^{j-1}C_j^i(m-1)^{j-i}m^{n-j+i}
\]

然后我们拎出\(m^{n-j}\),就可以得到:

\[\sum_{j=0}^{n-1}m^{n-j}\sum_{i=0}^{j-1}C_j^i(m-1)^{j-i}m^i
\]

那这样有什么好处呢?

回想一下二项式定理:\((x+y)^n=\sum_{i=0}^{n-1}x^iy^{n-i}\)。

这似乎与上面式子的后半部分有几分相似。

于是就可以化简得到:

\[\sum_{j=0}^{n-1}m^{n-j}((m-1)+m)^j=\sum_{j=0}^{n-1}m^{n-j}(2m-1)^j
\]

这个式子可以\(O(nlogn)\)快速幂计算,也可以直接\(O(n)\)计算。

总而言之,可以过了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000000
#define X 1000000007
#define Qinv(x) Qpow(x,X-2)
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
using namespace std;
int n,m;
I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}//快速幂
int main()
{
RI i,ans,p1,p2,b1,b2;
scanf("%d%d",&n,&m),ans=p1=Qpow(m,n),p2=1,b1=Qinv(m),b2=(1LL*2*m-1)%X;//初始化
for(i=0;i^n;++i) Inc(ans,1LL*p1*p2%X),p1=1LL*p1*b1%X,p2=1LL*p2*b2%X;//O(n)计算答案
return printf("%d",ans),0;//输出答案
}

【CF660E】Different Subsets For All Tuples(组合数学)的更多相关文章

  1. 【组合数学】cf660E. Different Subsets For All Tuples

    比较套路的组合数学题 For a sequence a of n integers between 1 and m, inclusive, denote f(a) as the number of d ...

  2. cf660E Different Subsets For All Tuples

    For a sequence a of n integers between 1 and m, inclusive, denote f(a) as the number of distinct sub ...

  3. 【CF660E】Different Subsets For All Tuples 结论题

    [CF660E]Different Subsets For All Tuples 题意:对于所有长度为n,每个数为1,2...m的序列,求出每个序列的本质不同的子序列的数目之和.(多个原序列可以有相同 ...

  4. Educational Codeforces Round 11 E. Different Subsets For All Tuples 动态规划

    E. Different Subsets For All Tuples 题目连接: http://www.codeforces.com/contest/660/problem/E Descriptio ...

  5. Codeforces 660E Different Subsets For All Tuples【组合数学】

    看了官方题解+q神的讲解才懂... 智商问题.. 讲道理..数学真的比脱单难啊... 题目链接: http://codeforces.com/problemset/problem/660/E 题意: ...

  6. Different Subsets For All Tuples CodeForces - 660E (组合计数)

    大意: 定义$f(a)$表示序列$a$本质不同子序列个数. 给定$n,m$, 求所有长$n$元素范围$[1,m]$的序列的$f$值之和. 显然长度相同的子序列贡献是相同的. 不考虑空串, 假设长$x$ ...

  7. FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅱ

    因为垃圾电脑太卡了就重开了一个... 前传:多项式Ⅰ u1s1 我预感还会有Ⅲ 多项式基础操作: 例题: 26. CF438E The Child and Binary Tree 感觉这题作为第一题还 ...

  8. 2019.03.14 ZJOI2019模拟赛 解题报告

    得分: \(100+100+0=200\)(\(T1\)在最后\(2\)分钟写了出来,\(T2\)在最后\(10\)分钟写了出来,反而\(T3\)写了\(4\)个小时爆\(0\)) \(T1\):风王 ...

  9. Codeforces 895.C Square Subsets

    C. Square Subsets time limit per test 4 seconds memory limit per test 256 megabytes input standard i ...

随机推荐

  1. jgroups-raft

    要求 Java 8 支持 实现服务器的动态添加和删除 文档的编写 基于复制计数器的共识算法实现 https://github.com/belaban/jgroups-raft

  2. vuex 浅认知

    什么是Vuex? Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式. 采用了集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 什么情况下我应该使用 ...

  3. vue 子组件调用父组件的函数

    子组件调用父组件的函数,使用$emit(eventName,[...args]),触发当前实例上的事件.附加参数都会传给监听器回调. 子组件 <template> <div> ...

  4. vue.js入门环境搭建

    1.node.js环境(npm包管理器) 2.vue-cli手脚架构建工具 3.cnpm npm的淘宝镜像 安装node.js 从node.js官网下载并安装node,安装过程一路“下一步”就可以 安 ...

  5. 关于i++与++i的学习讨论!

    先谈容易的知识点 区别两个 1. i++ 返回原来的值,++i 返回加1后的值. 2. i++ 不能作为左值,而++i 可以. 重点说下第二点.首先解释下什么是左值 左值是对应内存中有确定存储地址的对 ...

  6. 015 3Sum 三个数的和为目标数字

    Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all un ...

  7. 2019.03.21 读书笔记 基元类型的Parse与TryParse 性能与建议

    Parse转换失败时会抛出异常,耗损性能,如果转换成功,则与TryParse无差异.查看源码,tryparse的代码更多一些,在失败时,反而性能更优,主要是抛出异常耗损了性能.所以在不确定是用Tryp ...

  8. DRF-->1 序列化组件的使用和接口设计---get

    定义序列化器(本质就是一个类),一般包括模型类的字段,有自己的字段类型规则.实现了序列化器后,就可以创建序列化对象以及查询集进行序列化操作,通过序列化对象.data来获取数据(不用自己构造字典,再返回 ...

  9. Linux平台命令挂载U盘——实现数据共享

    废话少说,一一道来,Linux中按照步骤来做就可以啦.(嵌入式平台) 1.先看看本地的mount信息 # mountrootfs on / type rootfs (rw)/dev/root on / ...

  10. 【密码学】RSA密钥长度、明文长度和密文长度

    本文介绍RSA加解密中必须考虑到的密钥长度.明文长度和密文长度问题,对第一次接触RSA的开发人员来说,RSA算是比较复杂的算法,天缘以后还会补充几篇RSA基础知识专题文章,用最简单最通俗的语言描述RS ...