$\newcommand{stirf}[2]{{{#1}\brack{#2}}}$$\newcommand{stirs}[2]{{{#1}\brace{#2}}}$题意:$\sum\limits_{i=1}^mx_i\leq s$,对$\forall1\leq i\leq n,x_i\leq t$,求这个方程组的解数

做了几天总算是弄明白了...

会用到$\sum\limits_{k\leq n}\binom km=\binom{n+1}{m+1}$,这个直接归纳可证

方程$\sum\limits_{i=1}^nx_i=s,x_i\geq1$的解数是$\binom{s-1}{n-1}$,所以$\sum\limits_{i=1}^nx_i\leq s,x_i\geq1$的解数是$\binom sn$

枚举$x_{1\cdots n}$,答案即为$\sum\limits_{1\leq x_1\leq t}\cdots\sum\limits_{1\leq x_n\leq t}\binom{s-\sum\limits_{i=1}^n x_i}{m-n}$

如果去掉$\leq t$的限制,那么答案显然是$\binom sm$

所以对原问题考虑容斥,枚举至少有$k$个$x_i$不满足$x_i\leq t$的限制,将这些$x_i$减去$t$后就将限制变成了$1\leq x_i$,那么答案为$\sum\limits_{k=0}^n(-1)^k\binom nk\binom{s-kt}m$

接下来是构造,对于一个函数$f(x)$,对其$n$阶差分的结果为$\Delta^nf(x)=\sum\limits_{k=0}^n(-1)^{n+k}\binom nkf(x+k)$,令$f(x)=\binom{s-xt}m$,那么答案为$(-1)^n\Delta^nf(0)$

$f(x)$是一个$m$次多项式,写出它的牛顿级数$\sum\limits_{i=0}^mb_i\binom xi$并将其代入差分式中

$\begin{aligned}\Delta^nf(0)&=\sum\limits_{k=0}^n(-1)^{n+k}\binom nkf(k)\\&=\sum\limits_{k=0}^n(-1)^{n+k}\binom nk\sum\limits_{i=0}^mb_i\binom ki\\&=\sum\limits_{i=0}^mb_i\sum\limits_{k=0}^n(-1)^{n+k}\binom nk\binom ki\\&=\sum\limits_{i=0}^mb_i\binom ni(-1)^{n-i}\sum\limits_{k=0}^n(-1)^{k-i}\binom{n-i}{k-i}\\&=\sum\limits_{i=0}^mb_i\binom ni(-1)^{n-i}[n=i]\\&=b_n\end{aligned}$

所以我们只需求$b_n$,但为了求$b_n$,我们要先求$f(x)=\sum\limits_{i=0}^ma_ix^i$中的$a_i$,直接把下降幂展开成斯特林数即可,我们得到$a_i=\frac1{m!}\sum\limits_{j=i}^m(-1)^{m+i+j}\binom ji\stirf mjt^is^{j-i}$

$\begin{aligned}f(x)&=\sum\limits_{i=0}^ma_ix^i\\&=\sum\limits_{i=0}^ma_i\sum\limits_{j=0}^i\stirs ijx^{\underline j}\\&=\sum\limits_{j=0}^m\binom xj\sum\limits_{i=j}^ma_i\stirs ijj!\end{aligned}$

于是$b_n=\frac{n!(-1)^mt^n}{m!}\sum\limits_{i=0}^{m-n}\sum\limits_{j=0}^{m-n-i}(-1)^j\binom{n+i+j}j\stirs{n+i}n\stirf m{n+i+j}t^is^j$

差不多结束了,最后有一个小问题:求斯特林数

要求$\stirs nm$,虽然$n,m$都非常大,但$n-m$非常小,考虑$\stirs nm$的组合意义:将$n$个元素分为$m$个非空子集,因为最多有$n-m$个子集中的元素个数$\gt1$,设$g(n,m)$表示将$n$个元素分成$m$个子集,使得每个子集包含元素个数都$\gt1$的方案数,那么枚举$m$个子集中元素个数$\gt1$的子集个数$k$(剩下$m-k$个集合都只包含一个元素),我们得到$\stirs nm=\sum\limits_{k=0}^{n-m}\binom n{m-k}g(n-m+k,k)$

$g$的递推就和第二类斯特林数差不多了:$g(n,m)=m\cdot g(n-1,m)+(n-1)g(n-2,m-1)$

第一类也是类似的,只不过$g$的递推要相应地改成$g(n,m)=(n-1)g(n-1,m)+(n-1)g(n-2,m-1)$

于是我们可以$O\left((m-n)^2\right)$预处理并$O(m-n)$计算单个斯特林数,总的时间复杂度就是$O\left((m-n)^2\right)$了

数学真是一门化腐朽为神奇的学科==

#include<stdio.h>
typedef long long ll;
const int mod=1000000007;
int mul(int a,int b){return(ll)a*b%mod;}
int ad(int a,int b){return(a+b)%mod;}
void inc(int&a,int b){(a+=b)%=mod;}
int pow(int a,int b){
	int s=1;
	while(b){
		if(b&1)s=mul(s,a);
		a=mul(a,a);
		b>>=1;
	}
	return s;
}
int g1[210][210],g2[210][210],fac[210],rfac[210],inv[210];
void pre(int n){
	int i,j;
	g1[0][0]=g2[0][0]=1;
	for(i=1;i<=n;i++){
		for(j=1;j*2<=i;j++){
			g1[i][j]=mul(i-1,g1[i-1][j]);
			g2[i][j]=mul(j,g2[i-1][j]);
			if(i>1){
				inc(g1[i][j],mul(i-1,g1[i-2][j-1]));
				inc(g2[i][j],mul(i-1,g2[i-2][j-1]));
			}
		}
	}
	fac[0]=1;
	for(i=1;i<=n;i++)fac[i]=mul(fac[i-1],i);
	rfac[n]=pow(fac[n],mod-2);
	for(i=n;i>0;i--)rfac[i-1]=mul(rfac[i],i);
	inv[1]=1;
	for(i=2;i<=n;i++)inv[i]=-mul(mod/i,inv[mod%i]);
}
int binom(int n,int k){//k is small
	int i,s=1;
	for(i=0;i<k;i++)s=mul(s,n-i);
	return mul(s,rfac[k]);
}
int stirf(int n,int m){
	int i,t,s,b;
	s=0;
	b=binom(n,n-m);
	for(i=0;i<=n-m;i++){
		t=n-m+i;
		inc(s,mul(b,g1[t][i]));
		b=mul(b,mul(n-t,inv[t+1]));
	}
	return s;
}
int stirs(int n,int m){
	int i,t,s,b;
	s=0;
	b=binom(n,n-m);
	for(i=0;i<=n-m;i++){
		t=n-m+i;
		inc(s,mul(b,g2[t][i]));
		b=mul(b,mul(n-t,inv[t+1]));
	}
	return s;
}
int a[110],b[110];
class TrickyInequality{
	public:
		int countSolutions(ll s,int t,int n,int m){
			int i,j,res,pt,ps,bi;
			s%=mod;
			pre(200);
			for(i=0;i<=m-n;i++){
				a[i]=stirf(m,n+i);
				b[i]=stirs(n+i,n);
			}
			res=0;
			pt=1;
			for(i=0;i<=m-n;i++){
				ps=1;
				bi=1;
				for(j=0;j<=m-n-i;j++){
					inc(res,(j&1?-1:1)*mul(mul(mul(bi,b[i]),a[i+j]),mul(pt,ps)));
					ps=mul(ps,s);
					bi=mul(bi,mul(n+i+j+1,inv[j+1]));
				}
				pt=mul(pt,t);
			}
			res=mul(res,pow(t,n));
			for(i=n+1;i<=m;i++)res=mul(res,pow(i,mod-2));
			if((n+m)&1)res=-res;
			return(res+mod)%mod;
		}
};
/*
int main(){
	ll s;
	int t,n,m;
	TrickyInequality cl;
	scanf("%I64d%d%d%d",&s,&t,&n,&m);
	printf("%d",cl.countSolutions(s,t,n,m));
}
*/

[TCO2013]TrickyInequality的更多相关文章

  1. @topcoder - 2013TCO3A D1L3@ TrickyInequality

    目录 @description@ @accepted code@ @accepted code@ @details@ @description@ 现有不等式组: \[\begin{cases} x_1 ...

  2. [TCO2013]Block3Checkers

    题意:一个网格上有一些障碍和$3$个在网格边界上的棋子,你要添加一些障碍使得没有两个棋子四连通,问最少添加多少个障碍 官方题解——一张图教你做人... 三个棋子将网格边界分成三段,添加障碍后网格中一定 ...

  3. [TCO2013]LitPanels

    题意:一个$n\times m$的无色网格,你可以在其中选择两个$x\times y$的子矩形并在其中将其中任意的格子涂上颜色,问最终能得到多少种不同的网格 做这题会用到一个概念叫包围盒(boundi ...

  4. [TCO2013]DirectionBoard

    题意:给一个网格,每个格子有一个方向表示在这个格子上要往哪个方向走,你可以改变某些格子的方向,问最少多少次操作使得从任意格子出发都能回到这个格子 woc这都不会我还是回家种田去吧... 题目的要求是改 ...

随机推荐

  1. 你自认为理解了JavaScript?【转】

    第一题 if (!("a" in window)) { var a = 1; } alert(a); 第二题 var a = 1, b = function a(x) { x &a ...

  2. Android跳转到拨打电话的页面

    在Android6.0之后,拨打电话需要用户授予动态权限,项目中有此需求,有一种简单的方法,直接携带电话号码跳转到系统拨打电话的页面,很多应用也是这么做的,这样可以减轻工作量 代码如下: Androi ...

  3. spring-retry 重试机制

    业务场景 应用中需要实现一个功能: 需要将数据上传到远程存储服务,同时在返回处理成功情况下做其他操作.这个功能不复杂,分为两个步骤:第一步调用远程的Rest服务逻辑包装给处理方法返回处理结果:第二步拿 ...

  4. Perl6 Bailador框架(6):获取用户输入

    use v6; use Bailador; get '/' => sub { ' <html> <head><title></title>< ...

  5. vim查找/替换字符串【转】

    转自:http://www.cnblogs.com/GODYCA/archive/2013/02/22/2922840.html vi/vim 中可以使用 :s 命令来替换字符串.该命令有很多种不同细 ...

  6. 离线安装SDK

    1.下载android-sdk_rXX-windows.zip(XX为版本号,也可以下.exe版的不过没试过) 2.下载SDK 2.1.在浏览器输入http://dl-ssl.google.com/a ...

  7. JDBC数据源连接池(2)---C3P0

    我们接着<JDBC数据源连接池(1)---DBCP>继续介绍数据源连接池. 首先,在Web项目的WebContent--->WEB-INF--->lib文件夹中添加C3P0的j ...

  8. 简单理解Hash算法的作用

    什么是Hash Hash算法,简称散列算法,也成哈希算法(英译),是将一个大文件映射成一个小串字符.与指纹一样,就是以较短的信息来保证文件的唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到 ...

  9. linux命令(5):netstat命令

    网络监控:netstat –in [显示所有配置接口的状态] 查看端口状态:netstat -anlp | grep 8080 [显示8080端口列出的监听状态] 查看某个进程软件名:netstat ...

  10. hadoop 分布式环境安装

    centos 多台机器免密登录 hadoop学习笔记(五)--全分布模式下SSH免密码登陆的实现 参考安装教程 Hadoop-2.7.4 集群快速搭建 启动hadoop cd /opt/soft/ha ...