Every one will meet some difficult

###Description
求方程 ∑ i = 1 m x i &lt; = s \sum_{i=1}^{m}xi&lt;=s i=1mxi<=s且对于i=1~n, x i &lt; = t xi&lt;=t xi<=t的正整数解数。
n,m<=1e9,nt<=s<=1e18,m-n<=1e3

###Beat the Challeng
####Part 1
答案等于 ∑ i = 0 n ( − 1 ) i C n i C s − t i m \sum_{i=0}^{n}(-1)^iC_n^iC_{s-ti}^m i=0n(1)iCniCstim
大概思路是容斥然后用组合数计算。

####Part 2
我们先来介绍一下n阶差分公式
定义一次差分 Δ f [ i ] = f [ i + 1 ] − f [ i ] \Delta f[i]=f[i+1]-f[i] Δf[i]=f[i+1]f[i]
那么 Δ n f \Delta^n f Δnf为f经过n次差分之后所得的东西
一个结论: Δ n f [ x ] = ∑ i = 0 n ( − 1 ) n − i C n i f [ x + i ] \Delta^n f[x]=\sum_{i=0}^{n}(-1)^{n-i}C_n^if[x+i] Δnf[x]=i=0n(1)niCnif[x+i]
证明的话可以归纳,暴力展开证明
那么我们设 A n s = ( − 1 ) n a n s Ans=(-1)^{n}ans Ans=(1)nans, f [ i ] = C s − t x m f[i]=C_{s-tx}^{m} f[i]=Cstxm
可以发现 A n s = ∑ i = 0 n ( − 1 ) n + i C n i f [ i ] Ans=\sum_{i=0}^{n}(-1)^{n+i}C_n^if[i] Ans=i=0n(1)n+iCnif[i]
= ∑ i = 0 n ( − 1 ) n − i C n i f [ i ] =\sum_{i=0}^{n}(-1)^{n-i}C_n^if[i] =i=0n(1)niCnif[i]
= Δ n f [ 0 ] =\Delta^n f[0] =Δnf[0]

####Part 3
两类斯特林数及公式

第一类斯特林数 [ n m ] [_n^m] [nm]表示将m个可区分元素划分成n个不可区分圆排列的方案数
也有公式 P x m = ∑ i = 0 m ( − 1 ) m − i [ i m ] x i P_x^m=\sum_{i=0}^{m}(-1)^{m-i}[_i^m]x^i Pxm=i=0m(1)mi[im]xi
只是因为递推式相等罢了,因为不会打就用排列数代替下降幂了。。。

第二类斯特林数 { n m } {\{_n^m\}} {nm}表示将m个可区分元素划分成n个不可区分的集合的方案数
也有公式 x m = ∑ i = 0 m { i m } P x i x^m=\sum_{i=0}^{m}{\{_i^m\}}P_x^i xm=i=0m{im}Pxi
考虑一个组合问题"将m个可区分的球扔到n个可区分的箱子里的方案数"
显然答案是 n m n^m nm
再考虑枚举有球的箱子,假设有i个,那么我们需要将m个球划分成i个集合,然后对集合分配箱子。因为可区分所以是排列数。

####Part 4
回到原问题 f [ x ] = C s − t x m f[x]=C_{s-tx}^m f[x]=Cstxm
= 1 m ! P s − t x m ={1\over m!}P_{s-tx}^{m} =m!1Pstxm
= 1 m ! ∑ i = 0 m ( − 1 ) m − i [ i m ] ( s − t x ) i ={1\over m!}\sum_{i=0}^{m}(-1)^{m-i}[_i^m](s-tx)^i =m!1i=0m(1)mi[im](stx)i
= 1 m ! ∑ i = 0 m ( − 1 ) m − i [ i m ] ∑ j = 0 i ( − 1 ) j C i j s i − j t j x j ={1\over m!}\sum_{i=0}^{m}(-1)^{m-i}[_i^m]\sum_{j=0}^{i}(-1)^jC_i^js^{i-j}t^jx^j =m!1i=0m(1)mi[im]j=0i(1)jCijsijtjxj
= 1 m ! ∑ j = 0 m x j ∑ i = j m ( − 1 ) m − i + j [ i m ] C i j S i − j t j ={1\over m!}\sum_{j=0}^{m}x^j\sum_{i=j}^{m}(-1)^{m-i+j}[_i^m]C_i^jS^{i-j}t^j =m!1j=0mxji=jm(1)mi+j[im]CijSijtj
设后面那个∑中的东西为a[j],那么 f [ x ] = ∑ i = 0 m x i a [ i ] f[x]=\sum_{i=0}^{m}x^ia[i] f[x]=i=0mxia[i]
我们继续:
f [ x ] = ∑ i = 0 m x i a [ i ] f[x]=\sum_{i=0}^{m}x^ia[i] f[x]=i=0mxia[i]
= ∑ i = 0 m a [ i ] ∑ j = 0 i { j i } P x j =\sum_{i=0}^{m}a[i]\sum_{j=0}^{i}\{_j^i\}P_x^j =i=0ma[i]j=0i{ji}Pxj
= ∑ i = 0 m a [ i ] ∑ j = 0 i { j i } C x j j ! =\sum_{i=0}^{m}a[i]\sum_{j=0}^{i}\{_j^i\}C_x^jj! =i=0ma[i]j=0i{ji}Cxjj!
= ∑ j = 0 m C x j ∑ i = j m a [ j ] { j i } j ! =\sum_{j=0}^{m}C_x^j\sum_{i=j}^{m}a[j]\{_j^i\}j! =j=0mCxji=jma[j]{ji}j!
令后面那个∑中的式子为b[j],那么我们有 f [ x ] = ∑ i = 0 m C x i b [ i ] f[x]=\sum_{i=0}^{m}C_x^ib[i] f[x]=i=0mCxib[i]

####Part 5
回到原始式子,我们有 A n s = Δ n f [ 0 ] Ans=\Delta^nf[0] Ans=Δnf[0]
我们又得出了 f [ x ] = ∑ i = 0 m C x i b [ i ] f[x]=\sum_{i=0}^{m}C_x^ib[i] f[x]=i=0mCxib[i]
接下来我们给出一个结论:
如果 f [ x ] = ∑ i = 0 m C x i g [ i ] f[x]=\sum_{i=0}^{m}C_x^ig[i] f[x]=i=0mCxig[i]
那么 Δ n f [ x ] = ∑ i = 0 m g [ i ] C x i − n \Delta^nf[x]=\sum_{i=0}^{m}g[i]C_x^{i-n} Δnf[x]=i=0mg[i]Cxin
证明也可以暴力归纳。。。。

于是我们得出了 A n s = ∑ i = 0 m b [ i ] C 0 i − n Ans=\sum_{i=0}^{m}b[i]C_0^{i-n} Ans=i=0mb[i]C0in
A n s = b [ n ] Ans=b[n] Ans=b[n]
代回a和b我们可以得出 A n s = n ! m ! ∑ i = n m { n i } ∑ j = i m ( − 1 ) m − j + i C j i [ j m ] S j − i t i Ans={n!\over m!}\sum_{i=n}^{m}\{_n^i\}\sum_{j=i}^{m}(-1)^{m-j+i}C_j^i[_j^m]S^{j-i}t^i Ans=m!n!i=nm{ni}j=im(1)mj+iCji[jm]Sjiti
由于i和j的差不超过m-n,所以如果我们知道了需要的两类斯特林数可以O((m-n)^2)计算

####Part 6
正常做法可能需要O(m^2),我们需要从组合意义上来理解。
因为将m个元素放入n个集合/圆排列中,我们都需要至少在每一个集合/排列中放一个数。
那么我们元素大于1个的集合/排列不会超过m-n个,可以设F[i][j]表示将i个元素插入j个元素>1的集合/排列的方案数,然后直接Dp。
最终计算时枚举到底有几个元素>1的集合/排列

这样总复杂度就是O((m-n)^2)的了,足以通过本题
zrO 提供此题的wzd Orz
然而外校有人考场切?!

###Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

typedef long long ll;

const int N=2*1e3+5,Mo=1e9+7;

int pwr(int x,int y) {
	int z=1;
	for(;y;y>>=1,x=(ll)x*x%Mo)
		if (y&1) z=(ll)z*x%Mo;
	return z;
}

int n,m,mn,inv[N],ps[N];
int f[N][N],g[N][N],c[N][N],s[N],su[N];
ll S,T;

int C(int y,int x) {
	if (x>2*mn) x=y-x;
	return c[y-n][x];
}

int main() {
	freopen("success.in","r",stdin);
	freopen("success.out","w",stdout);
	scanf("%lld%lld%d%d",&S,&T,&n,&m);
	mn=m-n;S%=Mo;T%=Mo;

	fo(i,0,2*mn) inv[i]=pwr(i,Mo-2);
	ps[0]=1;fo(i,1,mn) ps[i]=(ll)ps[i-1]*S%Mo;

	fo(i,0,2*mn) {
		c[i][0]=1;
		fo(j,1,min(i+n,2*mn)) {
			c[i][j]=(ll)c[i][j-1]*(i+n-j+1)%Mo;
			c[i][j]=(ll)c[i][j]*inv[j]%Mo;
		}
	}

	f[0][0]=g[0][0]=1;
	fo(i,1,2*mn) 
		fo(j,1,i/2) {
			f[i][j]=(ll)f[i-1][j]*(i-1)%Mo;
			g[i][j]=(ll)g[i-1][j]*j%Mo;
			if (i>1) {
				(f[i][j]+=(ll)f[i-2][j-1]*(i-1)%Mo)%=Mo;
				(g[i][j]+=(ll)g[i-2][j-1]*(i-1)%Mo)%=Mo;
			}
		}

	fo(i,0,mn) 
		fo(j,0,min(m-(i+n),i+n))
			(su[i]+=(ll)f[m-(i+n)+j][j]*C(m,m-(i+n)+j)%Mo)%=Mo;

	fo(i,0,mn)
		fo(j,0,min(i,n))
			(s[i]+=(ll)g[i+j][j]*C(n+i,i+j)%Mo)%=Mo;

	int ans=0;
	fo(i,0,mn) {
		int sum=0,pt=pwr(T,i+n);
		fo(j,i,mn) {
			int res=(ll)C(n+j,n+i)*su[j]%Mo*ps[j-i]%Mo*pt%Mo;
			if ((m-j+i)&1) (sum+=Mo-res)%=Mo;
			else (sum+=res)%=Mo;
		}
		(ans+=(ll)sum*s[i]%Mo)%=Mo;
	}

	fo(i,n+1,m) ans=(ll)ans*pwr(i,Mo-2)%Mo;
	if (n&1) ans=Mo-ans;
	printf("%d\n",ans);
	return 0;
}

UPD(2019.1.1)
然而这道题被林立打爆了。。。。
考虑原式子的组合意义,相当于有n+1组,前n组有t个,最后一组有s-nt个,从中选出m个数,前n组至少选一个的方案数
生成函数为 [ x m ] ( ( x + 1 ) t − 1 ) n ( x + 1 ) s − n t [x^m]((x+1)^t-1)^n(x+1)^{s-nt} [xm]((x+1)t1)n(x+1)snt
考虑写成 [ x m − n ] ( ( x + 1 ) t − 1 x ) n ( x + 1 ) s − n t [x^{m-n}]({(x+1)^t-1\over x})^n(x+1)^{s-nt} [xmn](x(x+1)t1)n(x+1)snt
就只用保留前m-n项,直接暴力就好了
还可以用多项式取模做到O((m-n) log m-n log n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值