【题解】P6323 | 容斥 分拆数
本题存在低于
逆序对是大小关系,我们在小的那个数处统计每对逆序对,考虑从大到小插入每一个数,这样所有数都比他大,这样它插入在第
那么我们现在可以进行一个
重新回顾我们现在的问题:第
考虑没有
我们考虑容斥去掉限制,
钦定一些
问题变为对所有
这个问题直接做似乎还是只能
考虑经典的性质:最多选择了
证明:选择前
于是我们考虑从竖着一个数一个数 dp,换成横着一层一层 dp,从大到小加入每个数
让
分别表示:新加入一个数并往上垫高一层,往上垫高一层。
然后因为要求了每个数都不超过
于是我们在
代码:2024/6/20 提交时为最优解。
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define all(x) x.begin(),x.end()
#define FIN(x) freopen(#x,"r",stdin)
#define FOUT(x) freopen(#x,"w",stdout)
#define cerr(x) cerr << #x"= " << x << "\n"
#define rep(i,x,y) for(int i = (x) ; i <= (y) ; ++ i)
#define Rep(i,x,y) for(int i = (x) ; i >= (y) ; -- i)
#define SYNC(x) std :: ios :: sync_with_stdio (x); if (!x) {cin.tie(0);cout.tie(0);}
using std :: cin , std :: cout , std :: cerr ;
template<ll Mod>
struct math {
std :: vector <ll> fac , fiv , inv ;
ll pow (ll x , ll y = Mod - 2) {
ll res = 1 ;
for (x %= Mod ; y ; (x *= x) %= Mod , y >>= 1)
if (y & 1)
(res *= x) %= Mod ;
return res;
}
inline math () {}
inline math (int n) : fac(n + 1) , fiv(n + 1) , inv(n + 1) {
fac[0] = 1 ;
rep (i,1,n)
fac[i] = fac[i - 1] * i % Mod ;
fiv[n] = pow(fac[n]) ;
Rep (i,n,1)
fiv[i - 1] = fiv[i] * i % Mod ,
inv[i] = fac[i - 1] * fiv[i] % Mod ;
}
inline void init (int n) {
fac.resize(n + 1) , fiv.resize(n + 1) , inv.resize(n + 1) ;
fac[0] = 1 ;
rep (i,1,n)
fac[i] = fac[i - 1] * i % Mod ;
fiv[n] = pow(fac[n]) ;
Rep (i,n,1)
fiv[i - 1] = fiv[i] * i % Mod ,
inv[i] = fac[i - 1] * fiv[i] % Mod ;
}
inline ll binom (int n,int m) {
if (n < m || m < 0)
return 0;
return fac[n] * fiv[m] % Mod * fiv[n - m] % Mod ;
}
inline ll perm (int n,int m) {
if (n < m || m < 0)
return 0;
return fac[n] * fiv[n - m] % Mod ;
}
inline ll bracket (int x) {
return fac[x * 2] * fiv[x] % Mod * fiv[x + 1] % Mod ;
}
} ;
const int mod = 1e9 + 7 ;
inline void inc (int &tar,int ths) {
if ((tar += ths) >= mod)
tar -= mod ;
}
inline void dec (int &tar,int ths) {
if ((tar -= ths) < 0)
tar += mod ;
}
signed main( ) { SYNC (false);
int n , c ;
cin >> n >> c ;
math<mod> M (n + c) ;
std :: vector <int> f (c + 1) ;
f[0] = 1 ;
ll res = M.binom (c + n - 1 , n - 1) ;
for (int i = 1 ; i * (i + 1) / 2 <= c && i <= n ; ++ i) {
std :: vector <int> g(c+1) ;
rep (j,i,c) {
g[j] = f[j - i] ;
inc (g[j] , g[j - i]) ;
if (j >= n + 1)
dec (g[j] , f[j - n - 1]) ;
}
f.swap(g) ;
rep (j,0,c) {
(res += (i&1?mod-f[j]:f[j]) * M.binom (c - j + n - 1 , n - 1)) %= mod ;
}
}
cout << res << '\n' ;
}
更加本质的东西:
直接从生成函数和 Ferrers 图像的角度也可以得到相同复杂度的做法,上面那个容斥的本质是